Context 与 Ref 的边界
Context value 为什么会造成额外更新?
- 引用变化: 每次渲染新建的对象与函数在 Object.is 比较下不同,即使字段看似一样,也会通知消费者;
- context value 变化会重建整个子树;
function SessionProvider({ user, children }) {
const logout = useCallback(() => signOut(), []);
const value = useMemo(() => ({ user, logout }), [user, logout]);
return <SessionContext value={value}>{children}</SessionContext>;
}
如何惰性创建 ref 保存的纯对象?
- 参数求值:
useRef(new ExpensiveObject())的构造表达式每次渲染都会执行,虽然 React 只使用初次结果; - 初始化例外: current 为 null 时创建结果可预测且没有外部副作用的对象;
const cacheRef = useRef(null);
if (cacheRef.current === null) {
cacheRef.current = new Map();
}
如何只向父组件暴露有限的命令式能力?
- 句柄:
useImperativeHandle(ref, createHandle, dependencies?)把自定义对象暴露给父组件,可只开放 focus 而不开放任意 DOM 修改; - 依赖数组: 同 useEffect;
- Ref prop: React 19 函数组件直接接收 ref,内部另建 DOM ref;
import { useImperativeHandle, useRef } from "react";
function SearchInput({ ref }) {
const inputRef = useRef(null);
useImperativeHandle(
ref,
() => ({
focus() {
inputRef.current?.focus();
},
}),
[],
);
return <input ref={inputRef} />;
}