移除 Effect 依赖

有时,你 确实 希望 Effect 对某个值"做出反应",但该值的变化比你希望的更频繁------并且可能不会从用户的角度反映任何实际变化。例如,假设你在组件中创建了 options 对象,然后从 Effect 内部读取该对象:

js 复制代码
function ChatRoom() {
  const options = {
	 serverUrl: 'https://localhost:1234',
	 roomId: '音乐'
  };
  const [message, setMessage] = useState('');

  useEffect(() => {
    const connection = createConnection(options);
    connection.connect();
    return () => connection.disconnect();
  }, [options]); // ✅ 所有依赖已声明
  // ...

在每次重新渲染 ChatRoom 组件时,都会从头开始创建一个新的 options 对象。React 发现 options 对象与上次渲染期间创建的 options 对象是 不同的对象。这就是为什么它会重新同步 Effect(依赖于 options),并且会在你输入时重新连接聊天。

此问题仅影响对象和函数。在 JavaScript 中,每个新创建的对象和函数都被认为与其他所有对象和函数不同。即使他们的值相同也没关系!

如果该对象不依赖于任何 props 和 state,你可以将该对象移到组件之外:

js 复制代码
const options = {
  serverUrl: 'https://localhost:1234',
  roomId: '音乐'
};

function ChatRoom() {
  const [message, setMessage] = useState('');

  useEffect(() => {
    const connection = createConnection(options);
    connection.connect();
    return () => connection.disconnect();
  }, []); // ✅ 所有依赖已声明
  // ...

由于 createOptions 是在组件外部声明的,因此它不是响应式值。这就是为什么它不需要在 Effect 的依赖中指定,以及为什么它永远不会导致 Effect 重新同步。

将动态对象和函数移动到 Effect 中。如果对象依赖于一些可能因重新渲染而改变的响应式值,例如 roomId props,那么你不能将它放置于组件 外部。你可以在 Effect 内部 创建它:

js 复制代码
const serverUrl = 'https://localhost:1234';

function ChatRoom({ roomId }) {
  const [message, setMessage] = useState('');

  useEffect(() => {
    function createOptions() {
      return {
        serverUrl: serverUrl,
        roomId: roomId
      };
    }

    const options = createOptions();
    const connection = createConnection(options);
    connection.connect();
    return () => connection.disconnect();
  }, [roomId]); // ✅ 所有依赖已声明
  // ...

你可以编写自己的函数来组织 Effect 中的逻辑。只要将这些函数声明在 Effect 内部,它们就不是响应式值,因此它们也不是 Effect 的依赖。

从对象中读取原始值 ,有时,你可能会通过 props 接收到类型为对象的值:

js 复制代码
function ChatRoom({ options }) {
  const [message, setMessage] = useState('');

  useEffect(() => {
    const connection = createConnection(options);
    connection.connect();
    return () => connection.disconnect();
  }, [options]); // ✅ 所有依赖已声明
  // ...

这将导致 Effect 在每次父组件重新渲染时重新连接。要解决此问题,请从 Effect 外部 读取对象信息,并避免依赖对象和函数类型

js 复制代码
function ChatRoom({ options }) {
  const [message, setMessage] = useState('');

  const { roomId, serverUrl } = options;
  useEffect(() => {
    const connection = createConnection({
      roomId: roomId,
      serverUrl: serverUrl
    });
    connection.connect();
    return () => connection.disconnect();
  }, [roomId, serverUrl]); // ✅ 所有依赖已声明
  // ...

从函数中计算原始值。同样的方法也适用于函数。例如,假设父组件传递了一个函数:

为避免使其成为依赖(并导致它在重新渲染时重新连接),请在 Effect 外部调用它。这为你提供了不是对象的 roomId 和 serverUrl 值,你可以从 Effect 中读取它们:

js 复制代码
function ChatRoom({ getOptions }) {
  const [message, setMessage] = useState('');

  const { roomId, serverUrl } = getOptions();
  useEffect(() => {
    const connection = createConnection({
      roomId: roomId,
      serverUrl: serverUrl
    });
    connection.connect();
    return () => connection.disconnect();
  }, [roomId, serverUrl]); // ✅ 所有依赖已声明
  // ...

这仅适用于 纯 函数,因为它们在渲染期间可以安全调用。如果函数是一个事件处理程序,但你不希望它的更改重新同步 Effect,将它包装到 Effect Event 中。

摘要

  1. 依赖应始终与代码匹配。
  2. 当你对依赖不满意时,你需要编辑的是代码。
  3. 抑制 linter 会导致非常混乱的错误,你应该始终避免它。
  4. 要移除依赖,你需要向 linter "证明"它不是必需的。
  5. 如果某些代码是为了响应特定交互,请将该代码移至事件处理的地方。
  6. 如果 Effect 的不同部分因不同原因需要重新运行,请将其拆分为多个 Effect。
  7. 如果你想根据以前的状态更新一些状态,传递一个更新函数。
  8. 如果你想读取最新值而不"反应"它,请从 Effect 中提取出一个 Effect Event。
  9. 在 JavaScript 中,如果对象和函数是在不同时间创建的,则它们被认为是不同的。
  10. 尽量避免对象和函数依赖。将它们移到组件外或 Effect 内。
相关推荐
漂流瓶jz4 分钟前
理解Webpack插件机制:从插件使用、各类编译对象、Tapable到自定义插件与钩子开发
前端·javascript·webpack
北辰alk9 小时前
Next.js 全栈开发指南:从项目初始化到生产环境部署
react.js
梦帮科技10 小时前
GRAVIS v4.0:基于Web的极速套利架构设计与实时数据流实现
前端·人工智能·rust·自动化·区块链·智能合约·数字货币
爱勇宝11 小时前
办公资料反复修改、补传、交接混乱,我做了个桌面工具来解决这件事
前端·后端·程序员
微信开发api-视频号协议11 小时前
企业微信外部群开发自动化实践过程
java·前端·微信·自动化·企业微信·ipad
甲维斯12 小时前
Fable5:20美金的顶级设计师!
前端·人工智能
kyriewen12 小时前
我同时用了 Claude Code、Cursor 和 Codex,说说三个工具的真实差距——2026 年选错工具比不用 AI 更浪费时间
前端·ai编程·claude
Jackson__12 小时前
为了拯救我的腰椎和颈椎,我做了款浏览器插件!
前端·javascript·开源
闲猫12 小时前
Python FastAPI + SQLAlchemy 入门教程:从零搭建你的第一个 Web 应用
前端·python·fastapi
林小帅13 小时前
NestJS v11 + Prisma v7 ESM 迁移配置解析
前端·javascript·后端