eolas/Programming_Languages/React/Hooks/useCallback.md

71 lines
3 KiB
Markdown
Raw Normal View History

2022-07-12 15:42:08 +01:00
---
tags:
- Programming_Languages
- javascript
- react
- react-hooks
---
# `useCallback`
In short, React's useCallback hook is used to wrap functions. It tells React to not re-create a wrapped function when a component re-renders, unless any of the useCallback's dependencies change.
`useCallback` returns a memoized version of the callback function it is passed. This means that the function object returned from useCallback will be the same between re-renders.
Remember that in JavaScript, functions are objects. As a result, every time a component containing a function re-renders, it creates a new instance of the function in memory. If a function doesn't change in response to a UI event throughout the lifecycle of the component, there is no need for it to rerender, hence `useCallback` should be applied.
> Given the same dependency value, the `useCallback` hook returns the same function instance between renderings (aka memoization).
This said, for small functions that are not intensive, it doesn't really matter if they are not memoized.
## Syntax
A standard case of this would be a function that runs on a button click, for instance when sending data from a form to a server. In the example below there is quite a lot going on, and most of it is independent of the actual UI-cycle of the component.
```jsx
const handleSubmit = useCallback(
async (formValues) => {
setPendSaveConfig(true);
const payload = new GenerateConfig({
workflowId: project_id,
blockId: blockId,
config: formValues,
});
axios
.post(`${process.env.REACT_APP_ENDPOINT}/save-block-config`, payload)
.then((res) => console.log(res))
.finally(() => setPendSaveConfig(false))
.catch((err) => console.error(err));
},
[blockId, project_id],
);
```
Note that the syntax is similar to [useEffect](./useEffect.md): there is a dependency array. The effect is the same: the function contained within `useCallback` will only re-rendered if one of these dependencies changes. However (see next section) the function will run in its memoized form on every click.
## Reference versus result
`useCallback` only memoizes the function _object_ (the reference) not the value that is _returned_ by the function (the result).
In the example below, the `calculatePi()` function reference will not change between renders but each time the click event fires, the value returned by `calculatePi()` will change. In other words, it will be assigned fresh memory.
```jsx
function ParentComponent() {
const onHandleClick = useCallback(() => {
const special = calculatePi();
});
return <SubComponent handleClick={onHandleClick} />;
}
```
## Use cases
You should not apply `useCallback` in a blanket fashion, this can reduce performance rather than improve it. The best scenarios are:
1. A functional component wrapped inside React.memo() accepts a function object prop
2. When the function object is a dependency to other hooks, e.g. `useEffect(..., [callback])`
3. When the function has some internal state, e.g. when the function is debounced or throttled.