Javascript 在 React 中 useCallback/useMemo 有什么作用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/53159301/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What does useCallback/useMemo do in React?
提问by RTW
As said in docs, useCallback Returns a memoized callback.
正如在docs 中所说, useCallback 返回一个记忆化的回调。
Pass an inline callback and an array of inputs. useCallback will return a memoized version of the callback that only changes if one of the inputs has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders (e.g. shouldComponentUpdate).
传递内联回调和输入数组。useCallback 将返回回调的记忆版本,该版本仅在输入之一发生更改时才会更改。这在将回调传递给依赖引用相等的优化子组件时很有用,以防止不必要的渲染(例如 shouldComponentUpdate)。
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
But how does it work and where is the best to use it in React?
但是它是如何工作的,在 React 中使用它的最佳位置是什么?
P.S. I think visualisation with codepen examplewill help everyone to understand it better. Explained in docs.
PS 我认为使用codepen 示例进行可视化将有助于每个人更好地理解它。在文档中解释。
回答by Yangshun Tay
This is best used when you want to prevent unnecessary re-renders for better performance.
当您想要防止不必要的重新渲染以获得更好的性能时,最好使用它。
Compare these two ways of passing callbacks to child components taken from React Docs:
比较这两种将回调传递给从React Docs获取的子组件的方法:
1. Arrow Function in Render
1. Render 中的箭头函数
class Foo extends Component {
handleClick() {
console.log('Click happened');
}
render() {
return <Button onClick={() => this.handleClick()}>Click Me</Button>;
}
}
2. Bind in Constructor (ES2015)
2. 在构造函数中绑定(ES2015)
class Foo extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log('Click happened');
}
render() {
return <Button onClick={this.handleClick}>Click Me</Button>;
}
}
Assuming <Button>is implemented as a PureComponent, the first way will cause <Button>to re-render every time <Foo>re-renders because a new function is created in every render()call. In the second way, the handleClickmethod is only created once in <Foo>'s constructor and reused across renders.
假设<Button>实现为 a PureComponent,第一种方法将导致<Button>每次<Foo>重新渲染时重新渲染,因为在每次render()调用中都会创建一个新函数。在第二种方式中,该handleClick方法仅在<Foo>的构造函数中创建一次并在渲染中重复使用。
If we translate both approaches to functional components using hooks, these are the equivalents (sort of):
如果我们使用钩子将这两种方法转换为功能组件,则它们是等效的(有点):
1. Arrow Function in Render -> Un-memoized callback
1. Render 中的箭头函数 -> Un-memoized 回调
function Foo() {
const handleClick = () => {
console.log('Click happened');
}
return <Button onClick={handleClick}>Click Me</Button>;
}
2. Bind in Constructor (ES2015) -> Memoized callbacks
2. 在构造函数中绑定 (ES2015) -> 记忆化回调
function Foo() {
const memoizedHandleClick = useCallback(
() => console.log('Click happened'), [],
); // Tells React to memoize regardless of arguments.
return <Button onClick={memoizedHandleClick}>Click Me</Button>;
}
The first way creates callbacks on every call of the functional component but in the second way, React memoizes the callback function for you and the callback is not created multiple times.
第一种方式在功能组件的每次调用时都会创建回调,但在第二种方式中,React 会为您记忆回调函数,并且不会多次创建回调。
In most cases, it's fine to do the first way. As the React docs state:
大多数情况下,采用第一种方式就可以了。正如 React 文档所述:
Is it OK to use arrow functions in render methods? Generally speaking, yes, it is OK, and it is often the easiest way to pass parameters to callback functions.
If you do have performance issues, by all means, optimize!
可以在渲染方法中使用箭头函数吗?一般来说,是的,是可以的,而且通常是将参数传递给回调函数的最简单的方式。
如果您确实有性能问题,请务必进行优化!
回答by Barbu Barbu
I've made a small example to help others understand better how it behaves. You can run the demo hereor read the code bellow:
我做了一个小例子来帮助其他人更好地理解它的行为方式。您可以在此处运行演示或阅读以下代码:
import React, { useState, useCallback, useMemo } from 'react';
import { render } from 'react-dom';
const App = () => {
const [state, changeState] = useState({});
const memoizedValue = useMemo(() => Math.random(), []);
const memoizedCallback = useCallback(() => console.log(memoizedValue), []);
const unMemoizedCallback = () => console.log(memoizedValue);
const {prevMemoizedCallback, prevUnMemoizedCallback} = state;
return (
<>
<p>Memoized value: {memoizedValue}</p>
<p>New update {Math.random()}</p>
<p>is prevMemoizedCallback === to memoizedCallback: { String(prevMemoizedCallback === memoizedCallback)}</p>
<p>is prevUnMemoizedCallback === to unMemoizedCallback: { String(prevUnMemoizedCallback === unMemoizedCallback) }</p>
<p><button onClick={memoizedCallback}>memoizedCallback</button></p>
<p><button onClick={unMemoizedCallback}>unMemoizedCallback</button></p>
<p><button onClick={() => changeState({ prevMemoizedCallback: memoizedCallback, prevUnMemoizedCallback: unMemoizedCallback })}>update State</button></p>
</>
);
};
render(<App />, document.getElementById('root'));

