useMemo
useMemo返回一个memoized值
代码示例
const memoInfo = useMemo(() => info, [info])
- 把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。
- useMemo支持两个参数,第一个是创建的函数,第二个是依赖项数组,只有在依赖项数组发生变化时才会重新执行创建函数,用这种方法减少了渲染次数 🌰
const TestChild = memo(Test);
export default function App() {
const [info, set] = useState({ name: "li", age: 12 });
const change = (age) => {
set({
age: info.age + 1,
name: info.name
});
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2
onClick={() => {
set({ name: info.name, age: info.age + 1 });
}}
>
age: {info.age}
name: {info.name}
</h2>
<TestChild
info={useMemo(() => info, [info.name])}
/>
<TestChild
info={info}
/>
</div>
);
}
import React from "react";
const Test = (props) => {
console.log("render Test");
const onClick = () => {
props.onchage(props.info.age + 1);
};
return (
<div onClick={() => onClick()}>
<p>{props.info.age}</p>
</div>
);
};
export default Test;
代码中有两处引用了Test,区别为前者的参数是用useMemo包裹住的,后者没有;我们在点击h2标签的onClick方法时查看Test组件的渲染次数
结果只有一次,说明用useMemo包裹的参数并没有发生变化,所以第一个Test组件没有发生重新渲染
useMemo
那么问题来了,useMemo是怎么实现这个功能的?
我们首先找到react的源码
// https://github.com/facebook/react/blob/master/packages/react-reconciler/src/ReactFiberHooks.new.js
//创建useMemo
function mountMemo<T>(
nextCreate: () => T,
deps: Array<mixed> | void | null,
): T {
//初始化hook
const hook = mountWorkInProgressHook();
//拿到依赖项
const nextDeps = deps === undefined ? null : deps;
// 生成useMemo的返回值
const nextValue = nextCreate();
// 缓存返回值和当前依赖项
hook.memoizedState = [nextValue, nextDeps];
return nextValue;
}
//更新useMemo
function updateMemo<T>(
nextCreate: () => T,
deps: Array<mixed> | void | null,
): T {
// 拿到当前的hook
const hook = updateWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
// 取出hook的缓存值
const prevState = hook.memoizedState;
//对比当前依赖值和已经缓存值是否相等如果相同,返回原值否则返回新的对象
if (prevState !== null) {
// Assume these are defined. If they're not, areHookInputsEqual will warn.
if (nextDeps !== null) {
const prevDeps: Array<mixed> | null = prevState[1];
if (areHookInputsEqual(nextDeps, prevDeps)) {
return prevState[0];
}
}
}
const nextValue = nextCreate();
hook.memoizedState = [nextValue, nextDeps];
return nextValue;
}
useMemo又是如何对比新旧值呢?
答案就是Object.is() 感兴趣的话可以研究一下源码,方法areHookInputsEqual()