useCallback takes a callback function and an array of dependencies as arguments, and returns the cached callback function if each item in the dependency array remains the same.
useCallback can cache functions, wouldn’t all functions in the Function component be wrapped in
useCallback for the purpose of
React application optimization? Don’t worry, let’s take a look at two examples and decide which one is better,
The difference between
App2 is that
useCallback in the former and not in the latter. We know from the definition that
useCallback can cache functions, and that
App1 will not generate a new
value changes, so the first impression is that
App1 is definitely better.
App1 and determine which is better,
App1 is actually the same as the original
App1, but written in a different way, compared to
App2, which has one more array definition and one more
useCallback call than
App2, so contrary to the initial intuition,
App2 is better than
App1 which uses
performs better thanApp1
So you shouldn’t use
useCallback will lead to worse performance ?
Of course not,
useCallback can improve React’s performance, but only if it’s a prerequisite. Modify the above example to add a clear function to the input box:
In the above example,
ClearButton accepts props from
onClear and clears the input when the button is clicked. The problem with this example, however, is that when the
value changes, the
ClearButton is also re-rendered as seen in the
Console. From a performance point of view, a change in
value should not cause
ClearButton to re-render, because
ClearButton only relies on
onClear, but a change in
onClear to re-generate, resulting in
prevProps.onClear ! == nextProps.onClear, which causes
ClearButton to be re-rendered. This is where
useCallback comes in handy.
In the example above,
onClear is wrapped in
useCallback, so that a change in
value does not cause
onClear to be re-generated. But from the
Console, even with
useCallback, a change in
value still causes
ClearButton to be re-rendered.
This brings us back to the rendering of
React, where its own rendering must cause a re-rendering of the child component for the
React component, which can be verified by removing
onClear from the
In the above example, even though
ClearButton does not have any
value change still causes
ClearButton to be re-rendered. Why does this happen? Rewrite the
App above and it becomes clear.
The second argument to
React.createElement is the component’s
props, and you can see that even though
ClearButton doesn’t have any
props, each render of
App still passes a new empty object as its
props, which is why
ClearButton re-renders This is why
So how can we avoid this unnecessary rendering? The answer is the
shouldComponentUpdate lifecycle for Class components and
React.memo for Function components,
React.memo allow the developer to manually determine if the component needs to be re-rendered.
For the above example, simply wrapping
ClearButton would prevent
ClearButton from being re-rendered.
useCallback is not a silver bullet for
React performance optimisation, rather, the wrong use of it can lead to negative optimisation.
useCallback is syntactic sugar for
useCallback(fn, dependencies) is equivalent to
useMemo(() => fn, dependencies). As with
useMemo is not used as much as it should be, so when should you use
In the first case, as with
useCallback, when a child component uses
React.memo, the value calculated by
useMemo ensures that the
props remain the same, thus avoiding repeated rendering by the child component.
The second case is where the performance consumption of the value calculation exceeds the performance consumption of the call to
useMemo. Similar to the decomposition of
useCallback above, using
useMemo adds a computed function
fn generation, a dependency array
dependencies generation and a single call to
useMemo, if the value calculation requires more performance than the call to
useMemo, then using
useMemo is can be optimized.