Reputation: 574
What I want to do is sort of subscribe to a dispatch, then dispatch to another state. I've tried useEffect but it's giving me infinite loop and a few googling says to not update state on useEffect so now my code looks like this, but it's not working as intended.
const Chain = () => {
const [fooState, fooDispatch] = fooOne() // useReducer
const [barState, barDispatch] = barTwo() // useReducer
const btnOnClick = () => {
fooDispatch({ type: "UPDATE_FOO" })
// Update barState base on the new value of foo, doesn't work.
// Foo is not yet updated.
if (fooState.value == 'new value') {
barDispatch({ type: "UPDATE_BAR" })
}
// fooState gets updated after this function block.
}
return <Button label="Button" onClick={btnOnClick} />
}
export default Chain
My useReducer code looks like this: https://kentcdodds.com/blog/how-to-use-react-context-effectively
On line if (fooState.value == 'new value') {
, React still haven't updated the value so I can't go inside the if block.
Upvotes: 2
Views: 4204
Reputation: 4373
I think you should use useEffect
to keep the 2 reducer hooks in sync.
Hooks can be optimized to execute only when certain values change.
In your case, when fooState.value
(or fooState
if you don't want to be too strict).
Something like:
React.useEffect(() => {
if (fooState.value == 'new value') {
barDispatch({ type: "UPDATE_BAR" })
}
}, [fooState.value]);
should get you the behaviour you want - also remove barDispatch
from btnOnClick
The executing order should be something like:
fooDispatch
fooState
value which triggers a component re-render useEffect
to take action when fooState
changed and calls the barDispatch
If fooOne
and barTwo
are frequently used together maybe you should combine them in a single reducer hook.
I don't know of any reason why you shouldn't set state (or other hooks) in useEffect
. It is a bit tricky because you could get an infinite loop but there are cases where you need this.
I hope this helps!
Upvotes: 6
Reputation: 13077
Calls to dispatch
are asynchronous, so you can not read the state until the next rerender.
Also you should dispatch an action that says what happened, not what you want to happen, if that makes sense. Your reducer should conceptually react to the user interaction or other event that has just taken place. This is why it is called React.
So what this means is the instead of dispatching UPDATE_FOO
, you should dispatch BTN_CLICKED
and then both the FOO and BAR reducers should listen for this action and decide if they need to update.
Upvotes: 1