返回一个 memoized 值
// useMemo返回一个值(可以是函数)
const computeExpensiveValue = (a, b) => {
return a + b;
}
const memoizedValue = useMemo(computeExpensiveValue(a, b), [a, b]);
// useCallbak返回一个函数
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
- useMemo和useCallback解决的因函数更新而渲染自己的问题
- 它仅会在某个依赖项改变时才重新计算 memoized 值
- 传入
useMemo
的函数会在渲染期间执行 - 副作用属于
useEffect
的适用范畴,而不是useMemo
- 如果没有提供依赖项数组,
useMemo
在每次渲染时都会计算新的值 -
useCallback(fn, deps)
相当于useMemo(() => fn, deps)
。
与React.memo的区别
- react.memo解决的是因父组件state变化因为的自组件重复刷新的问题
- React.memo的用法
function MyComponent(props) {
}
function areEqual(prevProps, nextProps) {
// 手动判断是否需要重新渲染
// return true不渲染,false则渲染
}
export default React.memo(MyComponent, areEqual);
问题
-
React.memo
第二个参数不用的话默认就 props 浅比较 -
React.memo
在跟某些hooks配合使用的情况下会失效,例如在组件内部使用useState
,useReducer
,useContext
,当 state 或者 context 改变时,组件还是会重新渲染
import React, { useState } from "react";
function Child1(props) {
console.log("执行子组件1了");
return <div>子组件1上的n:{props.value}</div>;
}
function Child2(props) {
console.log("执行子组件2了");
return <div>子组件2上的m:{props.value}</div>;
}
const MChild1 = React.memo(Child1, () => {
return false; // 失效
}); // compare失效会直接导致整个React.memo失效
const MChild2 = React.memo(Child2);
export default function App() {
const [n, setN] = useState(0);
const [m, setM] = useState(10);
console.log("执行最外层盒子了");
// 这里与是否是箭头函数无关
function addM() {
setM(m + 1);
}
// 只要是复杂类型,都会渲染
const test = { a: 134 }; // 如果test是简单类型,则不会重复渲染
return (
<>
<div>
最外层盒子
<MChild1 value={n} test={test}/>
<MChild2 value={m} addM={addM} />
<button
onClick={() => {
setN(n + 1);
}}
>
n+1
</button>
<button
onClick={addM}
>
m+1
</button>
</div>
</>
);
}
问题
- 自定义的compare函数失效,导致整个React.memo失效
- App重新执行了,它会修改复杂数据类型的地址,从而引发重新渲染
- useMemo解决addN和addM地址变更引发的重复渲染的问题
import React, { useState, useMemo, useCallback, memo } from "react";
const Child1 = memo((props) => {
console.log("执行子组件1了");
return <div>子组件1上的n:{props.value}</div>;
})
const Child2 = memo((props) => {
console.log("执行子组件2了");
return <div>子组件2上的m:{props.value.m}</div>;
})
export default function App() {
const [n, setN] = useState(0);
const [m, setM] = useState({ m: 1 });
console.log("执行最外层盒子了");
const addN = useMemo(() => {
return () => {
setN(n + 1);
};
}, [n]);
const addM = useCallback(() => {
setM({ m: m.m + 1 });
}, [m]);
return (
<>
<div>
最外层盒子
<Child1 value={n} click={addN} />
<Child2 value={m} click={addM} />
<button onClick={addN}>n+1</button>
<button onClick={addM}>m+1</button>
</div>
</>
);
}
网友评论