useMemo hook
useMemo
hook
useMemo
是个可以在重渲染的过程中缓存计算结果的 React Hook。memo 使用方法为:
const cachedValue = useMemo(calculateValue, dependencies);
其中 calculateValue
是一个计算过的值,一般的用法是一个由返回值的函数,dependencies
是一个包含所有需要监控参数的数组,这个数组对于整个 memo 的过程来说非常的重要。useMemo
在第一次渲染时会返回 calculateValue
,在其他的渲染过程中,如果 dependencies
产生变化,那么就会重新调用 calculateValue
函数,并返回重新计算过的值。
这其实也算是一个 gocha,因为之前项目中出现了一个 bug 就是由 useMomo
造成的。
大概流程是使用 useMemo
缓存了一个值传到了公司内部开发的 UI 库中,UI 库返回了正确的数值,但是在我们使用的 wrapper 中,该值被 cache 了,因此 dependency 没有变化的情况下它就不会被重新渲染。
大概的案例如下:
const UIWrapper = ({ initialValue }) => {const [value, setValue] = useState(initialValue);const cachedValue = useMemo(() => 'some value here', [initialValue]);const handleUpdateVal = (someVal) => {setValue(someVal);};return <UI cachedValue={cachedValue} handleUpdateVal={handleUpdateVal} />;
};
其中 cachedValue
和 value
大概是在 UI 库中有一些依存关系,因此尽管 handleUpdateVal
中需要获取的值在 UI 中更新了,但是 handleUpdateVal
本身并没有被调用。因此,在使用第三方库时,使用 memoization 这个技巧还是需要更加的谨慎,并且需要判断数据之间是否存在依存关系,否则就有可能造成页面的不渲染。
其他一些 useMemo
的注意点
-
useMemo
使用 Object.is() 进行判断因此如果传入的值是一个对象,那么
useMemo
依旧进行重新计算,如:const obj = { a: 'a' };console.log(Object.is(obj, { a: 'a' }));
所以
useMemo
中不应该传入传入useState
创建的对象——每次渲染useState
都会创建一个新的对象,因此将这个值放入useMemo
的依赖中就没有任何的意义。解决方案:可以使用
useMemo
去 memo 通过useState
创建的对象本身。 -
useState
可以用来 memo React 组件 -
如果要使用
useMemo
去 memo 一个函数,不如使用 useCallback -
严格模式下 React 会渲染组件两次去判断函数是否为纯函数,这也是一个很好的 debug 方法去判断函数的输入和输出是否一致
-
useMemo
只因惊觉 🐔 你太美作为一个性能提升的方法,如果不使用useMemo
代码就无法正常工作,那么应该找到问题的关键,而不是依赖于useMemo
You should only rely on
useMemo
as a performance optimization. If your code doesn’t work without it, find the underlying problem and fix it first. Then you may adduseMemo
to improve performance.