useEffectEvent - This feature is available in the latest Canary version of React

Canary

useEffectEvent API 当前仅在 React Canary 和 实验发行版中可用

了解更多关于 React 版本发布的内容

useEffectEvent 是一个 React Hook,它可以让你将 Effect 中的非响应式逻辑提取到一个可复用的函数中,这个函数称为 Effect Event

const onSomething = useEffectEvent(callback)

参考

useEffectEvent(callback)

在组件的顶层调用 useEffectEvent 来声明一个 Effect Event。Effect Event 是你可以在 Effect 中调用的函数,例如 useEffect

import { useEffectEvent, useEffect } from 'react';

function ChatRoom({ roomId, theme }) {
const onConnected = useEffectEvent(() => {
showNotification('已连接!', theme);
});

useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.on('connected', () => {
onConnected();
});
connection.connect();
return () => connection.disconnect();
}, [roomId]);

// ...
}

在下方查看更多示例

参数

  • callback:一个包含你 Effect Event 逻辑的函数。当你使用 useEffectEvent 定义一个 Effect Event 时,callback 在被调用时总是可以访问到最新的 props 和 state。这有助于避免陈旧闭包问题。

返回值

返回一个 Effect Event 函数。你可以在 useEffectuseLayoutEffectuseInsertionEffect 中调用这个函数。

注意事项

  • 仅在 Effect 中调用:Effect Event 应该只在 Effect 中调用。在使用它的 Effect 之前定义它。不要将它传递给其他组件或 hooks。
  • 不是依赖数组的捷径:不要用 useEffectEvent 来避免在 Effect 的依赖数组中声明依赖。这可能会隐藏 bug 并让代码更难理解。更推荐显式依赖,或使用 ref 来比较之前的值。
  • 用于非响应式逻辑:仅在逻辑不依赖变化的值时使用 useEffectEvent 来提取。

用法

读取最新的 props 和 state

通常,当你在 Effect 中访问一个响应式值时,你必须把它包含在依赖数组里。这样可以确保当这个值改变时,Effect 会再次运行,这通常是期望的行为。

但在某些情况下,你可能只想在 Effect 中读取最新的 props 或 state,而不希望当这些值改变时让 Effect 重新运行。

要在 Effect 中读取最新的 props 或 state,而不让这些值成为响应式依赖,请把它们放进一个 Effect Event 中。

import { useEffect, useContext, useEffectEvent } from 'react';

function Page({ url }) {
const { items } = useContext(ShoppingCartContext);
const numberOfItems = items.length;

const onNavigate = useEffectEvent((visitedUrl) => {
logVisit(visitedUrl, numberOfItems);
});

useEffect(() => {
onNavigate(url);
}, [url]);

// ...
}

你可以将 url 这样的响应式值作为参数传递给 Effect Event。这让你可以访问最新的值,而不必因为这些值的改变而让 Effect 重新运行。