const resolveRef = useRef<(value: MergeResult) => void>();
const promiseRef = useRef<Promise<MergeResult>>(new Promise(resolve => {
resolveRef.current = resolve;
}));
这段代码有什么问题?
本意是在一个hook中维护同一个promise和其对应的resolve
因为ref在整个组件的生命周期里都维持对同一个对象的引用,所以浅显的以为这段代码会按预期工作
但并不是,因为我忽略了useRef(initialValue)的initialValue会多次运行,useRef 的初始化表达式会在每次渲染时执行(尽管返回值会被丢弃),所以resolveRef就总是指向这个新的resolve,promise和resolve对应不上自然不会按预期工作
那改成下面这种呢?
const resolveRef = useRef<(value: MergeResult) => void>();
const promiseRef = useRef<Promise<MergeResult>>(new Promise(resolve => {
if (!resolveRef.current) {
resolveRef.current = resolve;
}
}));
可以,或者
const resolveRef = useRef<(value: MergeResult) => void>();
const promiseRef = useRef<Promise<MergeResult>>();
useEffect(() => {
promiseRef.current = new Promise(resolve => {
resolveRef.current = resolve;
});
return () => {
resolveRef.current = undefined;
promiseRef.current = undefined;
};
}, []);
so,ref 的唯一性怎么保证的?
初始化阶段(mount)
调用 mountRef(initialValue)
时,通过 mountWorkInProgressHook
创建新的 Hook 对象,将其添加到当前 fiber 的 hook 链表中。
初始化 hook.memoizedState
为一个包含 current
属性的对象,初始值为传入的 initialValue
javascriptfunction updateRef<T>(initialValue: T): { current: T } {
const hook = updateWorkInProgressHook();
return hook.memoizedState; // 返回之前的 ref 对象
}
2. 更新阶段(update)
在 updateRef
中,通过 updateWorkInProgressHook
复用上一个生命周期的 Hook。
hook.memoizedState 保持不变,即 ref 对象始终指向同一实例,其 current 属性可动态修改而不触发渲染。
javascriptfunction mountRef<T>(initialValue: T): { current: T } {
const hook = mountWorkInProgressHook();
const ref = { current: initialValue };
hook.memoizedState = ref;
return ref;
}