Search code examples
javascriptreactjsreact-hooksuse-effectuse-state

React state not giving correct value on useEffect()


I'm trying to build a factorization algorithm using react. I would like to add results to LocalStorage based on results from factorization. However, LocalStorage sets previous results not current ones.

I think this is happening because useEffect runs on every new [number] (=user input) and not based on [results]. However, I need useEffect to run on new user input submition because that's when factorization has to be triggered.

How could I make localStorage set correct results after that factorization has completed (on the finally block if possible) ?

const [results, setResults] = useState({
  default: [],
  detailed: [],
  isPrime: '',
});

const { number } = props

useEffect(() => {
  handleWorker(number);
  //accessing results here will give previous results
}, [number]);

const handleWorker = number => {
  try {
    const worker = new Worker(new URL('facto.js', import.meta.url));
    worker.postMessage({ number, algorithm });
    worker.onmessage = ({ data: { facto } }) => {
      setResults({ ...facto });
      //the worker 'streams live' results and updates them on setResults
    };
  } catch(error) {
    console.log(error.message)
  } finally {
    localStorage.setItem(number, results)
    //here, results is not current state but previous one
  }
};

Please note that everything else works fine

Thanks


Solution

  • You are getting the previous value because localStorage.setItem is executed before setResults updates the state. Yo can do some refactor to make it work:

    const [results, setResults] = useState({
      default: [],
      detailed: [],
      isPrime: '',
    });
    
    const { number } = props;
    const workerRef = useRef(new Worker(new URL('facto.js', import.meta.url)));
    const worker = workerRef.current;
    
    useEffect(()=> {
        //-> create the listener just once
        worker.onmessage = ({ data: { facto } }) => {
          setResults({ ...facto }); 
        };
    }, []);
    
    useEffect(() => {
       //-> send message if number changed
       worker.postMessage({ number, algorithm });
    }, [number]);
    
    useEffect(() => {
       //-> update localStorage if results changed
       localStorage.setItem(number, results)
    }, [results]);