reactjsreact-hooksreact-state-management

How to solve Race condition in setting React state?


I have component that have state as object

const [data, setData] = useState({
  input, 
  output: '', 
  enableCopyToClipboard: true,
}

When listen to Observable I do following:

  // reset state before loading stream
  setData({ 
    ...data, 
    output: '',
    enableCopyToClipboard: false,
  });

  loadingStream(request).subscribe((response) => {
    resText.push(response.text);
    setData({ 
      ...data, 
      output: resText.join(''), 
    });
  });

Problem is my enableCopyToClipboard variable in state stays true when it should be false while streaming is ongoing. No idea why.


Solution

  • You can use the callback function to set the new data. So you'll always have the most up to date version of the state. This prevents the override of the old version of the state.

    // reset state before loading stream
    setData((prevData) => ({
      ...data,
      output: "",
      enableCopyToClipboard: false,
    }));
    
    loadingStream(request).subscribe((response) => {
      resText.push(response.text);
      setData((prevData) => ({
        ...prevData,
        output: resText.join(""),
      }));
    });
    

    You could also set the enableCopyToClipboard to false by default on the subscribe.

    loadingStream(request).subscribe((response) => {
      resText.push(response.text);
      setData((prevData) => ({
        ...prevData,
        enableCopyToClipboard: false,
        output: resText.join(""),
      }));
    });