A few React characteristics to keep in mind:

State Update is Asynchronous (slower than what you expect!)

  • State updates are asynchronous , so be careful with using the state immediately inside the same function. E.g. in the below, the state is not updated immediately after is called. Therefore, if we fetch data using the state, the value of would actually be before the update!
  • However, the useEffect hook is run after the state updates and DOM updates, our would get the updated value if placed inside a hook
  • If we are calling async/ await inside , this would not work in . It is because expects a clean-up function or nothing to be returned but functions return an implicit promise! We should define the fetchData functions separately instead of using the wrapping function
  • Since requires us to explicitly declare the dependencies in the array, it is best to define the functions and call it inside the useEffect functions so that we don’t need to worry about declaring as a dependency in !

Debounce and Re-render

Re-render = Reborn of var, func inside components

  • On each component re-render, the functions and the variables inside are created brand new and only the states are updated and preserved across the renders
  • Therefore, if we apply the debounced functions simply by itself inside a React component, debounced does not work as expected! Why?
  • Debounce works by terminating the intermediate function calls within the timeout period and therefore reduces the total number of functional invocations. e.g. if an user types ‘cat’ within a timeout of 300ms, a debounced onChange handler only invokes the function once with the input ‘cat’ because the previous invocations with input of ‘c’ and ‘ca’ are cancelled
Debounce image from CSS-Tricks https://css-tricks.com/debouncing-throttling-explained-examples/
Debounce image from CSS-Tricks https://css-tricks.com/debouncing-throttling-explained-examples/
Debounce Image from CSS-Tricks https://css-tricks.com/debouncing-throttling-explained-examples/
  • In React, this presents a dilemma because… 1. on state update, the React component re-renders 2. in each re-render, functions are created brand new and executed 3. It means that, the intermediate invocations of the debounced functions still get executed as the functions are brand new in each render, as they have no memory of the time lapsed from the previous render!
Red arrow shows executing debounce across re-rendering without useCallback
  • To solve this issue, we want the same function to be preserved and called throughout the re-rendering phase; therefore, useCallback comes to rescue!
  • returns a memoized version of the function that only changes when one of the dependencies changes. If the dependency does not change, the same function would be used across re-rendering and debounce as expected!
  • This gist contains more detailed example


A software engineer passionate about learning and growth