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 the newData 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 and ADD_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] })
        });
       }
    }
    

How many English words
do you know?
Test your English vocabulary size, and measure
how many words do you know
Online Test
Powered by Examplum