Calling 'setState' of hook within context sequentially to store data resulting in race condition issues

I've created a context to store values of certain components for display elsewhere within the app.

I originally had a single display component which would use state when these source components were activated, but this resulted in slow render times as the component was re-rendered with the new state every time the selected component changed.

To resolve this I thought to create an individual component for each source component and render them with initial values and only re-render when the source components values change.

i.e. for the sake of an example

const Source = (props) => {
    const { name, some_data} = props;
    const [setDataSource] = useContext(DataContext);

    useEffect(() => {
        setDataSource(name, some_data)
    }, [some_data]);

    return (
        ...
    );
}

const DataContextProvider = (props) => {

    const [currentState, setState] = useState({});

    const setDataSource = (name, data) => {
        const state = {
            ...currentState,
            [name]: {
                ...data
            }
        }
    }
    return (
        ...
    )
}


// In application 
<Source name="A" data={{
    someKey: 0
}}/>
<Source name="B" data={{
    someKey: 1
}}/>

The state of my provider will look like so;

{
  "B": {
    "someKey": 1
  }
}

I believe this is because setState is asynchronous, but I can't think of any other solution to this problem

1 answer

  • answered 2019-07-18 15:30 iofjuupasli

    You can pass the function to setState callback:

    setState((state) => ({...state, [name]: data}))
    

    It takes the latest state in argument in any case, so it always safer to use if your update depends on previous state.