-
Notifications
You must be signed in to change notification settings - Fork 11
possibility that the state from the store is inconsistent #10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
As far as I can tell, we call esamattis/redux-hooks#9 suggested the use of I'm interested in Please let me know if I confuse stale props/state with zombie components. |
Just merged #12. In summary, the stale props issue is almost solved. The exception is the rare case when the global state is updated between triggering rendering and actual rendering, which will only be resolved by next rendering right after rendering with stale props. The bad news is that this behavior is the limitation of hooks + subscription and it can't be helped. (One possible hack might be using useLayoutEffect and throwing a promise if it detects stale props. I wouldn't take that approach...) The good news is that this library is new and there's no backward compatibility issue like react-redux. |
By following the thread reduxjs/react-redux#1179, I'm pretty sure I misunderstood something. Zombie children is not just an issue of stale props, but an unrecoverable error caused by the stale props. I modified the example for react-hooks-easy-redux: modified example |
I'll remove |
love the prevision. wonder what additional examples we need. wonder if batchedUpdates 100% solves the issue of stale props. |
That's what I'm not sure either. Any breaking example would be nice. Since this is not only our problem, we keep eyes on reduxjs/react-redux#1179. |
yup, offload work upstream ;) |
Hi, author of
Unfortunately no. I've just recently discovered that my hooks implementation is still buggy in some cases. Using batchedUpdates lessens the impact a bit but does not solve it completely as shown here: https://codesandbox.io/s/p77jyzjkv7 Sadly currently it seems that there's no way to implement fully bug free Redux Hooks without a wrapping component. Or any single atom state management with hooks for that matter... |
@epeli Thanks for coming over! Yeah, I didn't expect that batchedUpdates solves 100% of the issue. Thanks for your example. https://codesandbox.io/s/2p4kxnxj1j The semantics of our library is totally different from that of react-redux. |
Looked bit more closely at this. It actually might be possible that batchedUpdates is enough for react-hooks-easy-redux because there's no map state happening before render execution. If I understand correctly it just forces component rendering when a used part of the state changes and the used parts are detected during the initial render? That's actually quite clever. |
Yeah, and because it doesn't have any local state.
Yes, and not only the initial render but also every render.
Glad to hear that. |
It's how I understand it. As I mention in my lib's issue there's a Batching chapter in the Dan's React as a UI Runtime -article which explains it. The issue in other Redux hooks lib is the map state phase: The map state executes immediately when the store updates so if the map state function is inside a render function and references parent props via closure those props can be based on the previous version of the state and can be incompatible with currento one. Your solution neatly dodges that :) UPDATE: Moved mutation suggestion to own issue #14 |
@epeli guess you need to change the top line of your readme yet again: UPDATE Nope. This is buggy too. And so is every other Redux Hooks lib. 😇 ps. I have thought of that |
Haha, I hope so! 😄 |
@theKashey how do you think the points @epeli brings up affects our plan to build selectors into the store, i.e:
@epeli FYI we are working on an improved redux that has something like this: const selectors = {
aSelector: (state, foo, bar) => ...,
}
createStore(reducer, selectors, etc)
const MyComponent = (props) => {
const state = useReduxState();
return <div>{state.aSelector(props.foo, props.bar)}</div>
}
In this system, selector returns are cached (not memoized) for use in potentially multiple places. And of course proxies (proxyequal) are used under the hood to determine updating, similar to reducers in this library. |
@theKashey my intuition says, our selectors also dont have this problem, yay! Check: @epeli 's redux-hooks: import {useMapState, useActionCreators} from "@epeli/redux-hooks";
const ActionCreators = {
inc() {
return {type: "INCREMENT"};
},
};
function Counter(props) {
const count = useMapState(state => state.count + props.baseValue); // CLOSURE!!
const actions = useActionCreators(ActionCreators);
return <button onClick={actions.inc}>{count}</button>;
} vs ours: const MyComponent = (props) => {
const state = useReduxState();
return <div>{state.aSelector(props.foo, props.bar)}</div>
} At the moment I'm not quite sure how the closure breaks things. Because if the problem is just using props in general, we'll still have the problem too. Thoughts?? |
Good. I've read the article and I assumed it is a natural behavior, but I wasn't 100% confident. Given that, I would like to close this issue, mainly because there's my misunderstanding at the beginning. @faceyspacey We can safely say that in most cases, we don't have the issue. There might be an edge case that we can't think of now, but that would be a new issue. |
@faceyspacey If the selector runs within the render phase it should be ok. |
regarding:
Are you referring to the react-redux issue that makes that library so much more complicated where they have to deal with "zombie components" ??
Truthfully, I never fully understood the issue. I always got close, but never spent the time to reproduce it so i could see it for myself.
If we have that issue still, unfortunately we have to solve it to be taken seriously. I recall that did it with nested usage of context in order to track the relationship between parent HOCs and descendant HOCs. So if, a parent is unsubscribed, insure the child also unsubscribes even if it has stale state that results in it it still rendering. Something like that I think was the issue.
The text was updated successfully, but these errors were encountered: