6

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

0

3 Answers 3

3
+100

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]);
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the explanation. So, it looks like React's flow of data update is conceptually correct but it contradicts with the finally {}'s workflow of ultimate code execution as found in most programming languages!
1

Here is what you need (probably):

const [results, setResults] = useState({ /* YOUR STATE */ });

const { number } = props

const handleWorker = useCallback((number) => {
  // DO WHATEVER YOU NEED TO DO HERE
},[]); // IF YOU DEPEND ON ANY MUTABLE VARIABLES, ADD THEM TO THE DEPENDENCY ARRAY

useEffect(() => {
  // DO WHATEVER YOU NEED TO DO HERE
  // INSTEAD OF localStorage.setItem(number, results)
  // DO localStorage.setItem(number, { ...facto })
}, [number,handleWorker]);

Let me know if it works.

1 Comment

Setting localStorage in the try block would not be very efficient since, as I mentionned, worker streams live results. localStorage would set many times the same number but with different results. It would be nice to have localStorage set results at the end only
-1

I think you can pass in the result state as dependent for the useEffect, so whenever the value of the result change , useEffect runs

useEffect(() => { //code goes here}, [results]);

Let say results also depends on a function handleWorker

useEffect(() => { //code goes here},
    [results,handleWorker]);

1 Comment

Since you will be using handleworker in the useEffect Function, you have to add it as a dependency, so whenever the result changes the useEffect function runs. Handle Worker is declared outside of the useEffect function

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.