useState hook setter incorrectly overwrites state

Welcome to the closure hell. This issue happens because whenever setState is called, state gets a new memory reference, but the functions changeValue1 and changeValue2, because of closure, keep the old initial state reference.

A solution to ensure the setState from changeValue1 and changeValue2 gets the latest state is by using a callback (having the previous state as a parameter):

import React, { useState } from "react";

const Test = () => {
  const [state, setState] = useState({
    value1: "1",
    value2: "2"
  });

  const changeValue1 = () => {
    setState((prevState) => ({ ...prevState, value1: "new 1" }));
  };
  const changeValue2 = () => {
    setState((prevState) => ({ ...prevState, value2: "new 2" }));
  };

  // ...
};

You can find a broader discussion about this closure issue here and here.


Your functions should be like this:

const changeValue1 = () => {
    setState((prevState) => ({ ...prevState, value1: "new 1" }));
};
const changeValue2 = () => {
    setState((prevState) => ({ ...prevState, value2: "new 2" }));
};

Thus you make sure you are not missing any existing property in the current state by using the previous state when the action is fired. Also thus you avoid to have to manage closures.