Accessing previous state within a useDispatch method
How do I access previous state inside the callback function in react? Because once I access data
it is always returning an initial state version, since I use useEffect
only on mount
const data = useSelector(({ state }) => state.data);
const dispatch = useDispatch();
useEffect(_ => {
dataService.loadData().then(resp => {
dispatch({ type: 'SET_DATA', payload: resp.data });
});
}, []);
const addData = newData => {
dataService.addData(newData).then(_ => {
// need the up to date state here for data
dispatch({ type: 'SET_DATA', payload: [newData, ...data] })
});
}
return <>
<button onClick={_ => addData({ name: "new name" })}></button>
{data.map(elem => <div>{elem.name}</div>)}
</>
2 answers
-
answered 2022-05-07 00:03
Drew Reese
I think you are not thinking about Redux correctly. You access the "previous" state in the reducer function. It's actually the current state, but the reducer function is a function of state and action, i.e. (state, action) => nextState.
The reducer function is the place to access the state you are trying to update.
Example:
const initialState = { ... other state properties ... data: [], }; const reducer = (state = initialState, action) => { switch(action.type) { ... other cases ... case SET_DATA: return { ...state, data: [action.payload, ...data], } default: return state; } };
The
addData
handler then just dispatches the action with thenewData
in the payload.const addData = newData => { dataService.addData(newData) .then(_ => { dispatch({ type: 'SET_DATA', payload: newData }) }); };
If you need to differentiate between loading the data and adding to it with regards to how it's handled and updates state, then I suggest using separate action types,
SET_DATA
andADD_DATA
for example. -
answered 2022-05-07 17:17
Lab Lab
So, digging through the stackoverflow and reading many react articles I found out that it is not possible to access the up to date value of state within the callback function with
useEffect
being called only once at mount.Though, it is not a problem if you are using class component.
For functional components, you need to use
dispatch
function, which has an access to the current state. So to update my data properly, I used the next code:const addData = newData => { dispatch(addDataDispatch(newData)); }
In your reducer:
export const addDataDispatch = newData => { return (dispatch, getState) => { const {state: {data}} = getState(); if (data.includes(newData)) return; dataService.addData(newData).then(_ => { dispatch({ type: 'SET_DATA', payload: [newData, ...data] }) }); } }
do you know?
how many words do you know