共计 3372 个字符,预计需要花费 9 分钟才能阅读完成。
useRef 和 useCallback 感觉是最容易了解的两个原生 use 了:
react hooks 实质摸索 – useRef 源码详解
react hooks 实质摸索 – useCallback 源码解析
因为之后要说的,都波及 ReactCurrentDispatcher$1 这个对象。
这个对象到底是什么意思?详见这里:(编辑中)
咱们间接看 useMemo 和 useEffect 的源码:
useMemo: function (create, deps) { | |
currentHookNameInDev = 'useMemo'; | |
// 这里详见 ReactCurrentDispatcher | |
mountHookTypesDev(); | |
// 很简略的函数:用于确认 deps 是不是数组,不是的话抛出谬误 | |
checkDepsAreArrayDev(deps); | |
// 更新 dispatch,详见 ReactCurrentDispatcher | |
// 这里这么写,是怕再 create 办法里有用到 use 类的办法,这样就会执行 InvalidNested 里的 hook 办法。var prevDispatcher = ReactCurrentDispatcher$1.current; | |
ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; | |
try {return mountMemo(create, deps); | |
} finally {ReactCurrentDispatcher$1.current = prevDispatcher;} | |
}, |
useEffect: function (create, deps) { | |
currentHookNameInDev = 'useEffect'; | |
// 这里详见 ReactCurrentDispatcher | |
mountHookTypesDev(); | |
// 很简略的函数:用于确认 deps 是不是数组,不是的话抛出谬误 | |
checkDepsAreArrayDev(deps); | |
return mountEffect(create, deps); | |
}, |
两者的区别只有 ReactCurrentDispatcher$1
局部。
为什么会有这个辨别? 因为 useMemo 是在渲染中的时候执行,而 useEffect 是在渲染后执行。
根据这个辨别,咱们能够正当猜想:只有有 ReactCurrentDispatcher$1 局部的 use,都是在渲染中执行。
只有这几个 use 是在渲染中执行:useMemo、useReducer、useState。
接下来看 useMemo 在 mount 和 update 时的源码(源码中,这两个函数就是连在一起的):
function mountMemo(nextCreate, deps) {var hook = mountWorkInProgressHook(); | |
var nextDeps = deps === undefined ? null : deps; | |
// nextCreate 就是咱们在创立 useMemo 时传入的函数。var nextValue = nextCreate(); | |
// 存入 hook 里,期待 update 时应用 | |
hook.memoizedState = [nextValue, nextDeps]; | |
return nextValue; | |
} | |
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]; | |
// 判断跟之前的 deps 值是否一样,如果一样,间接返回前值 | |
if (areHookInputsEqual(nextDeps, prevDeps)) {return prevState[0]; | |
} | |
} | |
} | |
// 这里开始,是判断 deps 值不一样的状况 | |
// 蕴含了前值或者以后值为 null 的状况,也认为是不一样。var nextValue = nextCreate(); | |
hook.memoizedState = [nextValue, nextDeps]; | |
return nextValue; | |
} |
updateMemo 函数的构造,跟 useCallback 的 update 很像:react hooks 实质摸索 – useCallback 源码解析
接下来看 useEffect 的 mount 和 update:
function mountEffect(create, deps) { | |
{ | |
// 这部分只跟 jest 相干,如同还和 fiber 相干,总之没关系。// $FlowExpectedError - jest isn't a global, and isn't recognized outside of tests | |
if ('undefined' !== typeof jest) {warnIfNotCurrentlyActingEffectsInDEV(currentlyRenderingFiber$1); | |
} | |
} | |
return mountEffectImpl(Update | Passive, Passive$1, create, deps); | |
} | |
function updateEffect(create, deps) { | |
{ | |
// $FlowExpectedError - jest isn't a global, and isn't recognized outside of tests | |
if ('undefined' !== typeof jest) {warnIfNotCurrentlyActingEffectsInDEV(currentlyRenderingFiber$1); | |
} | |
} | |
return updateEffectImpl(Update | Passive, Passive$1, create, deps); | |
} |
要害是 mountEffectImpl 和 updateEffectImpl:
function mountEffectImpl(fiberFlags, hookFlags, create, deps) {var hook = mountWorkInProgressHook(); | |
var nextDeps = deps === undefined ? null : deps; | |
currentlyRenderingFiber$1.flags |= fiberFlags; | |
// pushEffect 应该是把以后 effect 放到一个渲染队列中 | |
hook.memoizedState = pushEffect(HasEffect | hookFlags, create, undefined, nextDeps); | |
} | |
function updateEffectImpl(fiberFlags, hookFlags, create, deps) {var hook = updateWorkInProgressHook(); | |
var nextDeps = deps === undefined ? null : deps; | |
var destroy = undefined; | |
if (currentHook !== null) { | |
var prevEffect = currentHook.memoizedState; | |
destroy = prevEffect.destroy; | |
if (nextDeps !== null) { | |
var prevDeps = prevEffect.deps; | |
if (areHookInputsEqual(nextDeps, prevDeps)) {pushEffect(hookFlags, create, destroy, nextDeps); | |
return; | |
} | |
} | |
} | |
currentlyRenderingFiber$1.flags |= fiberFlags; | |
hook.memoizedState = pushEffect(HasEffect | hookFlags, create, destroy, nextDeps); | |
} |
这部分先不做具体解释,因为关涉的货色比拟多。
简略了解,就是 push 到了一个渲染队列里,在周期之外进行渲染
正文完
发表至: javascript
2022-03-12