useEffectEvent

useEffectEvent 是一个 React Hook,它允许你将非响应式逻辑从副作用中提取到一个名为 Effect 事件 的可重用函数中。

¥useEffectEvent is a React Hook that lets you extract non-reactive logic from your Effects into a reusable function called an Effect Event.

const onSomething = useEffectEvent(callback)

参考

¥Reference

useEffectEvent(callback)

在组件顶层调用 useEffectEvent 来声明副作用事件。Effect 事件是可以在副作用内部调用的函数,例如 useEffect

¥Call useEffectEvent at the top level of your component to declare an Effect Event. Effect Events are functions you can call inside Effects, such as useEffect:

import { useEffectEvent, useEffect } from 'react';

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

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

// ...
}

请参阅下面的更多示例。

¥See more examples below.

参数

¥Parameters

  • callback:包含副作用事件逻辑的函数。当你使用 useEffectEvent 定义副作用事件时,callback 始终会在调用时访问属性和状态中的最新值。这有助于避免过时闭包的问题。

    ¥callback: A function containing the logic for your Effect Event. When you define an Effect Event with useEffectEvent, the callback always accesses the latest values from props and state when it is invoked. This helps avoid issues with stale closures.

返回

¥Returns

返回一个副作用 Event 函数。你可以在 useEffectuseLayoutEffectuseInsertionEffect 中调用此函数。

¥Returns an Effect Event function. You can call this function inside useEffect, useLayoutEffect, or useInsertionEffect.

注意事项

¥Caveats

  • 仅在副作用内部调用:Effect 事件只能在副作用内部调用。在使用它们的副作用之前定义它们。不要将它们传递给其他组件或钩子。eslint-plugin-react-hooks linter(6.1.1 或更高版本)将强制执行此限制,以防止在错误的上下文中调用副作用事件。

    ¥Only call inside Effects: Effect Events should only be called within Effects. Define them just before the Effect that uses them. Do not pass them to other components or hooks. The eslint-plugin-react-hooks linter (version 6.1.1 or higher) will enforce this restriction to prevent calling Effect Events in the wrong context.

  • 非依赖快捷方式:不要使用 useEffectEvent 来避免在副作用的依赖数组中指定依赖。这会隐藏错误并使你的代码更难理解。如果需要,请优先使用显式依赖或使用引用来比较先前的值。

    ¥Not a dependency shortcut: Do not use useEffectEvent to avoid specifying dependencies in your Effect’s dependency array. This can hide bugs and make your code harder to understand. Prefer explicit dependencies or use refs to compare previous values if needed.

  • 用于非响应式逻辑:仅使用 useEffectEvent 来提取不依赖于值变化的逻辑。

    ¥Use for non-reactive logic: Only use useEffectEvent to extract logic that does not depend on changing values.


用法

¥Usage

读取最新的属性和状态

¥Reading the latest props and state

通常,当你访问副作用中的响应式值时,必须将其包含在依赖数组中。这确保了你的副作用在该值发生变化时再次运行,这通常是我们期望的行为。

¥Typically, when you access a reactive value inside an Effect, you must include it in the dependency array. This makes sure your Effect runs again whenever that value changes, which is usually the desired behavior.

但在某些情况下,你可能希望读取副作用内部最新的属性或状态,而不会在这些值发生变化时导致副作用重新运行。

¥But in some cases, you may want to read the most recent props or state inside an Effect without causing the Effect to re-run when those values change.

要在副作用中使用 读取最新的属性或 state,但又不使这些值具有响应性,请将它们包含在副作用事件中。

¥To read the latest props or state in your Effect, without making those values reactive, include them in an 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 应该在渲染后重新运行(以记录新的页面访问),但当 numberOfItems 发生变化时,它不应该重新运行。通过将日志逻辑封装在副作用事件中,numberOfItems 变为非响应式。它始终从最新值读取,而不会触发副作用。

¥In this example, the Effect should re-run after a render when url changes (to log the new page visit), but it should not re-run when numberOfItems changes. By wrapping the logging logic in an Effect Event, numberOfItems becomes non-reactive. It’s always read from the latest value without triggering the Effect.

你可以将像 url 这样的响应式值作为参数传递给副作用事件,以使其保持响应式,同时访问事件中最新的非响应式值。

¥You can pass reactive values like url as arguments to the Effect Event to keep them reactive while accessing the latest non-reactive values inside the event.