Reputation: 6236
According to React
docs :
useReducer is usually preferable to useState when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one.
1. can somebody explain me why useReducer
is not updating the state synchronously ?
const reducer = (state, action) => {
if( action.type === 'ADD_VALUE') {
console.log(`STATE IN REDUCER`, [...state, action.path]) // => ["1.1"]
return [...state, action.path]
}
}
const [state, dispatch] = useReducer(reducer, [])
<input type="button" onClick={() => {
dispatch({ type: 'ADD_VALUE', path: "1.1"})
console.log(`STATE`, state) // => []
// here i want to do some stuff based on the lastest updated state (["1.1"] and not [])
// for example dispatch an action with redux
}}/>
2. How can I do some stuff (dispatch a redux action) based on the lastest updated state (["1.1"]
and not []
) ?
Upvotes: 14
Views: 18172
Reputation: 5584
Use useEffect
to access the state correctly. You could add some safe-guarding if you want something invoking if a certain criterion is hit.
If you want to access your reducer across components, you can store the reducer using Context API. Look below for an example. You can see the reducer being injected into the Context on the parent component and then two child components that a) dispatches an action b) receives the update from the action.
1. Example of context reducer to use across multiple components
import React from "react";
import ReactDOM from "react-dom";
const Application = React.createContext({
state: null,
dispatch: null
});
function ActionComponent() {
const { dispatch } = React.useContext(Application);
return (
<div>
<div>Action Component</div>
<button onClick={() => dispatch("lol")}>Do something</button>
</div>
);
}
function ListenerComponent() {
const { state } = React.useContext(Application);
React.useEffect(
() => {
console.log(state);
},
[state]
);
return <div>Listener Component</div>;
}
function App() {
const [state, dispatch] = React.useReducer(function(state = [], action) {
return [...state, action];
});
return (
<Application.Provider value={{ state, dispatch }}>
<div className="App">
<ActionComponent />
<ListenerComponent />
</div>
</Application.Provider>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
2. Example of local reducer without using Application Context
const reducer = (state, action) => {
if( action.type === 'ADD_VALUE') {
return [...state, action.path]
}
}
const [state, dispatch] = useReducer(reducer, [])
React.useEffect(() => {
console.log(state);
}, [state]);
<input type="button" onClick={() => {
dispatch({ type: 'ADD_VALUE', path: "1.1"})
}}/>
Upvotes: 13