-
Notifications
You must be signed in to change notification settings - Fork 103
High level API discussion: do we even need useMappedState #39
Comments
One potential issue with this approach is that it requires either a somewhat awkward syntax ( |
To be clear I'm not suggesting this particular API. Just that the notion of running a selector that involves props to determine a bailout has a lot of pitfalls (such as handling stale props), and can cause other issues in concurrent mode (such as the current code which mutates refs during rendering). It doesn't really map to the React conceptual model nicely. From React's point of view, props don't really exist until you render — but this Hook is trying to "bail out" at arbitrary times outside rendering. One alternative design could be to allow selectors but only static ones: import {createSelector} from 'react-redux-hook'
const useTodosLength = createSelector(state => state.allTodos.length)
function Todos() {
const todosLength = useTodosLength()
return <h1>Total: {todosLength}</h1>
} If you need to select based on a prop value, you can do this with a component layer: import {createSelector} from 'react-redux-hook'
const useTodos = createSelector(state => state.allTodos)
function Todos() {
const todos = useTodos()
return todos.map(todo => <Todo {...todo} />)
}
const Todo = React.memo(() => {
// ...
}) Essentially, in this case the selecting component is your |
I'd add that attempts to get rid of component nesting at all costs seem a bit misguided to me. You'll need component nesting for features like Suspense anyway. It's not an anti-pattern by itself. Component nesting is unnecessary when there's no hierarchy. But in this case, there is. In case where it's not "vertical" (hoisted selector), you don't need nesting. Like in my second proposal. But when selector itself depends on props, I think you do. |
This is then very similar to using a factory function for |
I also think it's tempting to underestimate problems caused by stale props. But the whole history of React Redux bindings is trying to work around this problem in various ways. This is why it's really tempting to me to not have this problem at all, at the cost of some conciseness.
This kind of API can probably be extended to handle that too. I don't see why not — as long as props don't appear in the middle. |
The question of what a "proper" React+Redux+hooks API should look like is interesting. But, in all honesty, I haven't dug into it seriously yet myself, because we need to work through other issues with React-Redux first before we can deliver a public hooks-based API (per reduxjs/react-redux#1177 ). We do have an open thread for bikeshedding potential hooks API designs at reduxjs/react-redux#1179 . It's got some discussion, but I haven't paid attention to it yet. I agree that with hooks, you can do a lot of the extraction / memoization work right there in the component itself. However, one of the key objectives of React-Redux has always been to keep the app performant, especially given Redux's global update subscription behavior. Dan and I have talked about this a few times, and I know he and I don't see eye to eye on this, but: All the benchmarks and investigation we've done show that doing the comparisons and extraction first, and only triggering a re-render if the derived data has changed, ultimately results in better performance, because React only has to re-render when there's an actual change. Forcing re-renders for every state change, regardless of whether there's a component that will actually update, is always going to be more overhead. I do definitely agree that the "stale props" issue is a major aspect to take into consideration overall. |
This has been my experience as well. Basically staying out of React as long as possible yields the best performance. But, I would love to be proven wrong on this.
This is one of those issues that a library either has to solve for you or avoid entirely, since it isn't a problem until it is, and then it is a big problem and hard to diagnose. |
What's a good benchmark? @markerikson |
Well, what we've got atm is the React-Redux benchmarks suite at https://github.com/reduxjs/react-redux-benchmarks . I'm not going to claim those are "good", necessarily, but it's at least something that provides concrete objective numbers to compare with. |
I would like to share that I tried running one of benchmark scenarios by @markerikson to compare this library and react-redux, and some others. |
Using |
It definitely depends on your app and would require careful profiling. We found that swapping out |
Closing this out for now since I don't think we are going to drastically change the API. |
@ianobermiller : out of curiosity, how much use is this library still getting now that React-Redux ships an "official" hooks API? |
My guess is as good as yours. Judging by NPM stats, people are still using it, but it isn't growing much. We use it internally for a few products at Facebook. My sense is that there is still a demand for a lighter weight way to use hooks with Redux. Do you see |
I don't see us creating a separate package, if that's what you're asking. As far as I know, the vast majority of React-Redux usage is still That said, I could imagine that some apps might only actually want to use the hooks. The better question is whether I just opened up an issue to investigate whether we can tree shake or not: |
@gaearon and I were discussing a mismatch in the model of hooks and
react-redux
. To quote some of our conversation:The idea is that
useMappedState
is hard to implement efficiently (it has grown pretty ugly already) and easily because it is really trying to recreate much of what React hooks already do.The example code would basically use components as containers and selectors, similar to
connect
:And
useStoreState
could look something like (stripped down for brevity):Basically it just passes the entire state to the React component.
If you wanted to put them all in a single component:
Or if you want one container and multiple children:
The text was updated successfully, but these errors were encountered: