Search code examples
javascriptreactjsreact-hooksuse-stateusecallback

React prevent re-render by using functional variant of useState


I am trying to understand the exact difference in terms of how the re-render of function component is caused in one case using plain setState V/s other case which uses functional state update

The relevant code snippet is as below

Case 1 : Causes re-render of the component

const onRemove = useCallback(
  tickerToRemove => {
    setWatchlist(watchlist.filter(ticker => ticker !== tickerToRemove));
  },
  [watchlist]
);

Case 2 : Does not cause re-render

const onRemove = useCallback(tickerToRemove => {
  setWatchlist(watchlist =>
    watchlist.filter(ticker => ticker !== tickerToRemove)
  );
}, []);

Full example of both the use-cases can be seen on;

https://codesandbox.io/s/06c-usecallback-final-no-rerenders-bsm64?file=/src/watchlistComponent.js

https://codesandbox.io/s/06b-usecallback-usememo-ngwev?file=/src/watchlistComponent.js:961-970

UPDATE

Full article link https://medium.com/@guptagaruda/react-hooks-understanding-component-re-renders-9708ddee9928#204b

I am a bit confused as to how the re-render of child components is prevented.

In the article it says

"Thankfully, setter function from useState hook supports a functional variant which comes to our rescue. Instead of calling setWatchlist with the updated watchlist array, we can instead send a function that gets the current state as an argument"

However, I am a bit confused whether the re-rendering of child components is prevented because we use empty array (as [] does not changes between renders) V/s prevented because of using setter variant of useState hook ?


Solution

  • Using a functional state update or not is rather irrelevant to the question you are asking about. You appear to be asking why (1) a callback with dependency triggers a rerender versus (2) a callback with empty dependency.

    The answer is quite literally very simple. In version (2) you are providing a stable callback reference from the time the component mounts that never changes, whereas in (1) the callback reference changes when the dependency does. Remember that React components rerender when state or props update (a new callback reference is a new prop reference) or when the parent component rerenders. Since the onRemove prop is updating in (1) it triggers a rerender.