这次来看useCallback。useCallback是所有原生use中比较简单的函数
其实整体跟useRef/useState相似。
咱们间接看源码。
初始化的时候,次要执行如下代码:
function mountCallback(callback, deps) { // 获取以后钩子,也就是链表指针 var hook = mountWorkInProgressHook(); // deps是useCallback的第二个参数,也就是什么状况下须要更新callback var nextDeps = deps === undefined ? null : deps; // 两个值存到hook.memoizedState,也是hooks这套代码的常见伎俩 hook.memoizedState = [callback, nextDeps]; // 返回callback。就是传入什么,返回什么。 return callback;}
要害是第二次渲染functional component时做的事件:
function updateCallback(callback, deps) { // 通用做法。 var hook = updateWorkInProgressHook(); // 获取以后的依赖值,是一个数组 var nextDeps = deps === undefined ? null : deps; // 获取之前的依赖值,用于比照的。也是一个数组,这个数组中[1]的值才是依赖值 var prevState = hook.memoizedState; // 检测确定prevState存在。什么状况不存在?临时不晓得 if (prevState !== null) { // 检测nextDeps存在。这一行和上一行的判断是能够合并的。 if (nextDeps !== null) { // 后面说道,prevState上[1]的值才是之前的依赖值。 var prevDeps = prevState[1]; // 判断以后的依赖的值和之前依赖的值是否相等 if (areHookInputsEqual(nextDeps, prevDeps)) { // prevState[0]就是之前的那个callback,阐明函数没变,还是那个 return prevState[0]; } } } // 这里是prevState不存在,或者nextDeps(以后值)和prevDeps(前值)不同 // 或者nextDeps不存在(等于是变动了,也就是说,如果第二个参数传入null,每次都会从新定义函数) hook.memoizedState = [callback, nextDeps]; // 返回新函数 return callback;}
附上areHookInputsEqual的源码:
function areHookInputsEqual(nextDeps, prevDeps) { { if (ignorePreviousDependencies) { // Only true when this component is being hot reloaded. return false; } } if (prevDeps === null) { { error('%s received a final argument during this render, but not during ' + 'the previous render. Even though the final argument is optional, ' + 'its type cannot change between renders.', currentHookNameInDev); } return false; } { // Don't bother comparing lengths in prod because these arrays should be // passed inline. if (nextDeps.length !== prevDeps.length) { error('The final argument passed to %s changed size between renders. The ' + 'order and size of this array must remain constant.\n\n' + 'Previous: %s\n' + 'Incoming: %s', currentHookNameInDev, "[" + prevDeps.join(', ') + "]", "[" + nextDeps.join(', ') + "]"); } } // 只有这部分是重要的,这里是做了浅比拟。 for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) { if (objectIs(nextDeps[i], prevDeps[i])) { continue; } return false; } return true;}