React·100 questions

How to correctly work with setTimeout/setInterval timers?

Answer

Working with timers and intervals in React requires strict adherence to component lifecycle management rules, as improper handling of asynchronous functions often leads to bugs and memory leaks. The most common mistake is creating timers directly in the component body without taking re-rendering cycles into account, which causes new background processes to spawn on every little interface change. For a correct implementation, timers should always be placed inside an effect hook, which controls their launch depending on a given dependency array. At the same time, it is critically important to return a cleanup function that calls standard timer cancellation methods, preventing them from running endlessly in the background.

A particular complexity is the use of repeating intervals in combination with the concept of closures in JavaScript. Since effects capture variables from the scope of the render in which they were created, the interval may use outdated data, unaware of changes in state or props. To solve this problem, developers actively use the pattern of storing current values in special mutable references that do not trigger a re-render when their content changes. This allows the interval to always access fresh data without the need to constantly restart the timer itself on every change of local variables.

If the logic of working with time intervals becomes complex and includes many conditions, pauses, and resumptions, the best architectural solution is to move this functionality into a separate custom hook. This approach allows you to isolate all complex math and timer work from the visual part of the component, making the code clean and easy to understand. The separation of concerns between presentation and background processes makes the application more resilient to errors and simplifies writing automated tests.

Always create timers inside an effect hook and clear them using appropriate functions in the return block.
Use mutable references to store current values to avoid problems with stale closures inside intervals.
Move complex time management logic into custom hooks to unload the main interface components.
Was this answer helpful?

More questions in this topic

Related questions from other topics