react|react hooks 本质探索 - useMemo、useEffect源码解析
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 = https://www.it610.com/article/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 = https://www.it610.com/article/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);
}
【react|react hooks 本质探索 - useMemo、useEffect源码解析】这部分先不做详细解释,因为牵涉的东西比较多。
简单理解,就是push到了一个渲染队列里,在周期之外进行渲染
推荐阅读
- react的”Hello|react的”Hello World !“
- 学习笔记02
- React内部的性能优化没有达到极致()
- react函数组件使用React.memo避免重复渲染
- react-pdf|react-pdf 打造在线简历生成器的示例代码
- 【Copy攻城狮日志】React|【Copy攻城狮日志】React Native 集成 HMS Core
- react中的双向绑定你真的了解吗
- react|react 源码中位运算符的使用详解
- 你知道怎么在|你知道怎么在 HTML 页面中使用 React吗
- Three.js+React使二维图片呈现3D效果