hooks-useMemo和useCallback
先上案例
function FunctionComponent(props) {
//
const [state, dispatch] = useState(1);
const [state2, dispatch2] = useState(1);
const memoValue=useMemo(()=> state+state2,[state,state2]);
const computed= useCallback(
() => {
return state+state2;
},
[state,state2],
)
return (
<div className="border">
<p onClick={()=>{
dispatch(2);
}}>{props.name}{state}{state2}{memoValue}{computed}</p>
</div>
);
}
mountMemo 和mountCallback
mountMemo初始化时,执行传递的第一个函数,并返回得到的值。保存在fiber上的是值和依赖项,用于更新检测,mountCallback在fiber保存的是函数和依赖项。
function mountMemo(nextCreate, deps) {
var hook = mountWorkInProgressHook();
var nextDeps = deps === undefined ? null : deps;
var nextValue = nextCreate();
hook.memoizedState = [nextValue, nextDeps];
return nextValue;
}
function mountCallback(callback, deps) {
var hook = mountWorkInProgressHook();
var nextDeps = deps === undefined ? null : deps;
hook.memoizedState = [callback, nextDeps];
return callback;
}
updateMemo和updateCallback
updateMemo 很简单,其实就是在更新的时候判断了一下依赖项是否有变化,没有变化,返回原本fiber返回的值,updateCallback同样的道理,只不过返回的是回调函数而已。
function updateMemo(nextCreate, deps) {
var hook = updateWorkInProgressHook();
var nextDeps = deps === undefined ? null : deps;
var prevState = hook.memoizedState;
if (prevState !== null) {
// Assume these are defined. If they're not, areHookInputsEqual will warn.
if (nextDeps !== null) {
var prevDeps = prevState[1];
if (areHookInputsEqual(nextDeps, prevDeps)) {
return prevState[0];
}
}
}
var nextValue = nextCreate();
hook.memoizedState = [nextValue, nextDeps];
return nextValue;
}
// 遍历fiber上保存的依赖项和变化后的依赖项值,用OBject.is检测
var objectIs = typeof Object.is === 'function' ? Object.is : is;
function updateCallback(callback, deps) {
var hook = updateWorkInProgressHook();
var nextDeps = deps === undefined ? null : deps;
var prevState = hook.memoizedState;
if (prevState !== null) {
if (nextDeps !== null) {
var prevDeps = prevState[1];
if (areHookInputsEqual(nextDeps, prevDeps)) {
return prevState[0];
}
}
}
hook.memoizedState = [callback, nextDeps];
return callback;
}
总结
useMemo为什么可以做一些性能方面的优化?
- 因为useMemo在依赖项没有变化的时候不会执行回调函数,直接读取fiber上的数据,所以可以达到缓存的目的
useCallback又有什么作用呢?
-
useCallback和useMemo是同样的道理,缓存的是函数而已,不用再次申明,而我们可以利用来控制子组件不必要的更新
例: 有一个父组件,其中包含子组件,子组件接收一个函数作为props;通常而言,如果父组件更新了,子组件也会执行更新;但是大多数场景下,更新是没有必要的,我们可以借助useCallback来返回函数,然后把这个函数作为props传递给子组件;子组件监听callback,依赖项是通过Object.is来判断的,callback是定义好的,没有变化。就可以确保不会触发setState等驱动视图更新的情况。Object.is他的判断范围:
都是 undefined
都是 null
都是 true 或 false
都是相同长度的字符串且相同字符按相同顺序排列
都是相同对象(意味着每个对象有同一个引用)
都是数字且
都是 +0
都是 -0
都是 NaN
或都是非零而且非 NaN 且为同一个值