0

Maybe I'm missing something, but I can't find a solution for that.

I have a React component and want to run some periodic background job (setInterval) This job use some information of the components state and should also be able to change that.

My component:

export default function Form() {
   const [state, setState] = useState<IState>(initialState);
   useEffect(() => {
      //init component and other stuff
     
      // trigger background Task
      setInterval(backgroundJob, 10000);

   }, []);

   function backgroundJob(){
      state.xxx
   }

   function handleButtonClick(){
     state.xxx = state.xxx + 1;
     setState({
       ...state,
     });
   }   
}

The main problem is, the backgroundJob Function is able to access the state, but it's only the initalState. If the state is updated, (e.g. on a button click via the handleButtonClick() function), the next Interval tick still has old values in the state

Do I misunderstood some basic concept here?

Evil_skunk
  • 3,040
  • 4
  • 30
  • 42
  • Can you add sandbox of this? – Shubham Verma Sep 02 '20 at 12:08
  • I've just asked more or less the same: https://stackoverflow.com/questions/63701210/update-multiple-times-same-state-from-asynchronous-callback And reading: https://stackoverflow.com/questions/54069253/usestate-set-method-not-reflecting-change-immediately https://stackoverflow.com/questions/55342406/updating-and-merging-state-object-using-react-usestate-hook solved my problem. – Ricardo Garcia Landete Sep 02 '20 at 12:11

1 Answers1

1

You need to add backgroundJob to you dependency list, but also you need to clear this interval when the effect is re-run:

Note that in the way your code is written this will happen every time the component renders. You can use useCallback to optimize if needed.

useEffect(() => {
  //init component and other stuff
  // trigger background Task
  const intervalId = setInterval(backgroundJob, 10000);

  return () => clearInterval(intervalId)

}, [backgroundJob]);

In not doing so, the backgroundJob you are running is the one from the first render which only "see"s (via its closure) the initial state (AKA Stale Closure)

thedude
  • 9,388
  • 1
  • 29
  • 30
  • unfortunately that doesn't solve my problem well. My state is changing quite often, so this solution will often clear the interval and restart it again. So if my state changes every second, the background job is never executed :-( – Evil_skunk Sep 02 '20 at 12:32
  • You could use `useCallback` to depend only on specific parts of your state, or `useRef` for often changing values – thedude Sep 02 '20 at 12:58