Skip to main content

优化-细节

info

建议不要在 hooks 的参数中执行函数或者 new 实例

const hook1 = useRef(fn());
const hook2 = useRef(new Fn());

原因:

  • 首先函数每次 rerender 都会执行 hooks ,那么在执行 hooks 函数的同时,也会执行函数的参数,比如上面的代码片段中的 fn() 和 new Fn(),也就是每一次 rerender 都会执行 fn 或者是 new 一个实例。这可能不是开发者期望的,而执行函数,或创建实例也成了一种性能浪费,在一些极端情况下,可能会造成内存泄漏,比如在创建新的 dom 元素,但是没有进行有效的回收。

  • 在 hooks 原理章节讲到过,函数组件在初始化和更新流程中,会使用不同的 hooks 对象,还是以 useRef 为例子,在初始化阶段用的是 mountRef 函数,在更新阶段用的是 updateRef 函数,开发者眼睛看见的是 useRef,在 React 底层却悄悄的替换成了不同的函数。 更重要的是大部分的 hooks 参数都作为初始化的参数,在更新阶段压根没有用到,那么传入的参数也就没有了意义,回到上述代码片段,fn() 和 new Fn()在更新阶段根本就没有被 useRef 接收, 无辜的成了流浪者。

以 useRef 为例:

初始化阶段
function mountRef(initialValue) {
const hook = mountWorkInProgressHook();
const ref = { current: initialValue };
hook.memoizedState = ref;
return ref;
}
  • 初始化的时候用到了 initialValue ,也就是第一个参数。
更新阶段
function updateRef(initialValue) {
const hook = updateWorkInProgressHook();
return hook.memoizedState;
}
  • 在更新阶段根本没有用到 initialValue。

那么如果开发者真的想在 hooks 中,以函数组件执行结果或者是实例对象作为参数的话,那么应该怎么处理呢。这个很简单,可以用 useEffect 包装一下。

const hook = useRef(null);
useEffect(() => {
hook.current = new Fn();
}, [changeValue]);