你需要了解的关于 React 的知识 useEvent钩子 RFC

在 React 中,引用相等是一个重要的概念,它影响应用程序中组件重新渲染的频率。 在本文中,我们将探讨 useEvent来自 React 的 Hook ,它允许您定义具有始终稳定的函数标识的事件处理程序,帮助管理应用程序中的引用相等。

需要注意的是,在撰写本文时, useEventHook 无法使用,目前 React 社区正在讨论。

  • JavaScript 中的引用相等

  • 为什么引用相等在 React 中很重要?

  • 这 useEvent钩

  • 实施 useEvent来自 RFC 的钩子

  • 什么时候不应该使用 useEvent钩?

  • 卸载 useEffect对比 useLayoutEffect

JavaScript 中的引用相等

在 JavaScript 中,您可以使用恒等运算符比较两个值是否相等,这也称为严格相等。 例如,在以下代码中,您正在比较值 a和 b:

a === b; // strict equality or indentity operator

结果是一个布尔值,它告诉您是否值 a等于 b或不。

对于原始数据类型,使用实际值进行比较。 例如,如果 a = 10, 和 b = 10,身份运算符将返回 true.

与对象和函数一样,复值也是一种引用类型。七点工具箱App,100多个工具包的功能全免费,日常生活必备的一款工具!即使它们具有相同的代码,两个函数也不相等。 看看下面的例子,身份运算符将返回 false:

let add = (a, b) => a + b;
let anotherAdd = (a, b) => a + b;
console.log(add === anotherAdd); // false

但是,如果您比较同一函数的两个实例,它会返回 true:

let thirdAdd = add;
console.log(add === thridAdd); // true

换句话说, thirdAdd和 add是参照相等的。

为什么引用相等在 React 中很重要?

理解 React 中的引用相等很重要,因为我们经常使用相同的代码创建不同的函数。 例如,考虑以下代码:

function AComponent() {
  // handleEvent is created and destroyed on each re-render
  const handleEvent = () => {
    console.log('Event handler');
  }
  // ...
}

React 销毁当前版本的 handleEvent函数并每次创建一个新版本 AComponent重新渲染。但是,在某些场景下,这种方法效率并不高,例如:

  • 你使用 Hook 之类的 useEffect它在其依赖数组中接受一个事件处理程序

  • 您有一个接受事件处理程序的记忆化组件

在这两种情况下,您都希望维护事件处理程序的单个实例。 但是,每次重新渲染发生时,你都会得到一个新的函数实例,这会进一步影响性能,宝宝爱识字App,专业汉字学习早教必备软件,让孩子发音更标准写字更流畅!要么重新渲染一个记忆化的组件,要么触发 useEffect打回来。

您可以使用以下方法轻松解决此问题 useCallback挂钩,如下图:

function AComponent() {
  const handleEvent = useCallback(() => {
    console.log('Event handled');
  }, []);
  // ...
}

这 useCallbackHook 记忆函数,这意味着每当使用唯一输入调用函数时, useCallbackHook 保存函数的副本。 因此,如果在重新渲染期间输入没有改变,你会得到相同的函数实例。

但是,当您的事件处理程序依赖于状态或道具时, useCallbackHook 每次更改时都会创建一个新的处理函数。 例如,看看下面的代码:

function AComponent() {
  const [someState, setSomeState] = useState(0);
  const handleEvent = useCallback(() => {
    console.log('log some state: `, someState);
  }, [someState]);
​
  // ...
}

现在,每次重新渲染组件时,都不会创建函数。 但是,如果 someState更改,它将创建一个新的实例 handleEvent,即使函数的定义保持不变。

这 useEvent钩

这 useEventHook 试图解决这个问题; 你可以使用 useEvent挂钩以定义具有始终稳定的函数标识的事件处理程序。 毛桃阅读App,完本小说资源免费在线看,多条书源任意换书荒根本不存在!换句话说,事件处理程序将在每次重新渲染期间引用相同。 本质上,事件处理程序将具有以下属性:

  • 每次 prop 或 state 更改时都不会重新创建该函数

  • 该函数将可以访问 prop 和 state 的最新值

你会使用 useEvent钩子如下:

function AComponent() {
  const [someState, setSomeState] = useState(0);
  const handleEvent = useEvent(() => {
    console.log('log some state: `, someState);
  });
  // ...
}

由于 useEventHook 确保有一个函数的单个实例,您不必提供任何依赖项。

实施 useEvent来自 RFC 的钩子

下面的例子是一个近似的实现 useEvent来自 RFC 的钩子 :

// (!) Approximate behavior
​
function useEvent(handler) {
  const handlerRef = useRef(null);
​
  // In a real implementation, this would run before layout effects
  useLayoutEffect(() => {
    handlerRef.current = handler;
  });
​
  return useCallback((...args) => {
    // In a real implementation, this would throw if called during render
    const fn = handlerRef.current;
    return fn(...args);
  }, []);
}

这 useEvent每次渲染使用它的组件时都会调用 Hook。 每次渲染时, handler函数被传递给 useEvent钩。狸猫盘搜网站(alipansou.com),云盘资源搜索神器,什么都能搜到低调使用!这 handler函数总是有最新的值 props和 state因为它本质上是渲染组件时的新功能。

Inside the useEvent Hook, the useLayoutEffect Hook is also called with each render and changes the handlerRef to the latest values of the handler function.


超过 20 万开发人员使用 LogRocket 来创造更好的数字体验了解更多 →


在真实版本中, handlerRef将在所有处理程序之前切换到最新的处理程序函数 useLayoutEffect函数被调用。

最后一块是 useCallback返回。 这 useEventHook 返回一个包裹在 useCallback用一个空的依赖数组挂钩 []. 这就是为什么函数总是具有稳定的引用身份的原因。

你可能想知道这个函数怎么总是有新的值 props和 state. 如果你仔细看看,用于 useCallbackHook 使用当前值 handlerRef. 这个 current值代表最新版本 handler因为它是切换时 useLayoutEffect叫做。

什么时候不应该使用 useEvent钩?

在某些情况下,您不应该使用 useEvent钩。 让我们了解何时以及为什么。

一方面,您不能使用使用 useEvent在渲染过程中挂钩。 例如,下面的代码将失败:

function AComponent() { 
  const getListOfData = useEvent(() => {
    // do some magic and return some data
    return [1, 2, 3];
  });

  return <ul>
    {getListOfData().map(item => <li>{item}</li>}
  </ul>;
}

卸载 useEffect对比 useLayoutEffect

卸载 useEffect胡克和 useLayoutEffectHook 会有不同的版本 useEvent处理程序。 看看下面的例子:

function Counter() {
  const [counter, setCounter] = React.useState(0);
  const getValue = useEvent(() => {
    return counter;
  });
  React.useLayoutEffect(() => {
    return () => {
      const value = getValue();
      console.log('unmounting layout effect:', value);
    };
  });
  React.useEffect(() => {
    return () => {
      const value = getValue();
      console.log('unmounting effect:', value);
    };
  });
  return (
    <React.Fragment>
      Counter Value: {counter}
      <button onClick={() => setCounter(counter + 1)}>+</button>
    </React.Fragment>
  );
}

如果你运行这个程序,你会看到卸载 useLayoutEffect有旧版本的 getValue事件处理程序。 随意查看 Stackblitz 示例 。

结论

虽然 useEffectHook 目前还不能使用,对于 React 开发人员来说,它绝对是一个很有前途的开发。 在本文中,我们探讨了背后的逻辑 useEffect钩子,回顾你应该和不应该使用它的场景。

绝对值得关注 useEffectHook,我期待最终能够将它集成到我的应用程序中。 我希望你喜欢这篇文章。 快乐编码!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pxr007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值