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]);
// ...
}
参数
¥Parameters
-
callback
:包含副作用事件逻辑的函数。当你使用useEffectEvent
定义副作用事件时,callback
始终会在调用时访问属性和状态中的最新值。这有助于避免过时闭包的问题。¥
callback
: A function containing the logic for your Effect Event. When you define an Effect Event withuseEffectEvent
, thecallback
always accesses the latest values from props and state when it is invoked. This helps avoid issues with stale closures.
返回
¥Returns
返回一个副作用 Event 函数。你可以在 useEffect
、useLayoutEffect
或 useInsertionEffect
中调用此函数。
¥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.