Search code examples
reactjselectronipcframe-rate

is there problem on executing an event handler thousand of times a second inside an useEffect?


sorry for the (maybe) newbie question, i have this simple react code inside an electron app:

const MainScreen = () => {
 const [values, setValues] = useState<number[]>([]); // 4 float values
 useEffect(() => {
    window.sensor.onRawData((data) => {
      setValues(data);
    });
    return () => {
      window.sensor.offRawData();
    };
 }, []);

..........
}

that receive event from Electron IPC and update a state variable, when i slow down the sending thread and receive 100 msg/sec all is good, but when i will receive 1000/2000+ msg/sec React will start to show this warning:

**Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.**

I don't know why, is there a limit on how many times a second a function must be called in React?

Thanks!


Solution

  • is there a limit on how many times a second a function must be called in React?

    No, not exactly a limit, more like overhead for react to do what it does.

    Consider this: every time you call setValues react has to mark this element and the subtree as outdated, schedule a rerender - and eventually, apply the 100-200 state changes that happened since it last rendered, run the code in your component, create and compare the returned subtree to the old one and apply the changes to the DOM which then potentially triggers layouting, styles and rerenders on the browser side.

    You're asking a lot of react/your computer to do all this 1000-2000 times per second.

    If you have such a high volume of updates may I suggest a different approach:

    useEffect(() => {
        let tmp = values;
    
        window.sensor.onRawData((data) => {
            // tracking the latest values
            tmp = data;
        });
    
        // updating the state with the latest values (and forcing a rerender) 
        // at most every 100ms.
        const interval = setInterval(setValues, 100, () => tmp);
    
        return () => {
            window.sensor.offRawData();
            clearInterval(interval);
        };
    }, []);
    

    In the end, no matter how fast your computer is how many values/s your sensor can produce and how many FPS your monitor can render; how many new values/s on the screen can you process?