【问题标题】:useEffect and dependency arrayuseEffect 和依赖数组
【发布时间】:2022-04-21 10:23:05
【问题描述】:

我试图了解 react useEffect 如何处理对象。

这里有一个例子可以帮助我演示我的问题:

export function UseEffectHook() {
  const initialState = {
    firstName: "Joe",
    lastName: "Smith",
    address: {
      home: "123 street"
    }
  };
  const [user, setUser] = useState(initialState);
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log("triggered");
  }, [user]);

  return (
    <div>
      <p>useEffect - Practice with different deps</p>
      {JSON.stringify(user)}
      <label>Firstname:</label>

      <input
        type="text"
        onChange={e => setUser({ ...user, firstName: e.target.value })}
      />
      <br />
      <label>Lastname:</label>
      <input
        type="text"
        onChange={e => setUser({ ...user, lastName: e.target.value })}
      />
      <button onClick={() => setCount(count + 1)}>Button</button>
   </div>
  );
}

我已经读过,将对象作为依赖项放在 useEffect 挂钩中不起作用,因为对象是如何在重新渲染之间进行比较的。

我最初的想法是在这个例子中点击按钮和更新计数也应该导致 useEffect 钩子被更新。情况并非如此,useEffect 不会重新运行。

我无法找到足够人为的示例来帮助演示 useEffect 何时以及为何使用对象重新运行。任何帮助将不胜感激。

【问题讨论】:

  • 如果想让count触发useEffect,需要添加到依赖数组:[user, count]
  • 也许我的例子太做作而没有效果,但我知道添加计数会触发useEffect。我的目标是查看何时以及如何将对象添加到 useEffect 导致重新渲染,因为在 js 中比较对象的方式
  • 我刚刚对其进行了测试,它也适用于对象

标签: reactjs react-hooks


【解决方案1】:

只要对象更改引用,useEffect 将使用其依赖数组中的对象重新运行。

例如,在您的代码中,用户在您调用 setUser 之前始终是稳定的,在这种情况下,它将更改为新的引用并在该点运行。

如果您在每次渲染中将用户定义为一个新对象,那么每次重新渲染组件时都会运行 useEffect。

  const user = {
    firstName: 'Joe',
    lastName: 'Smith',
    address: {
      home: '123 street',
    },
  };

这都是关于参照平等的。每次渲染时是否 previousUser===newUser。 React 本质上对依赖数组中的每个变量执行一个非常相似的检查(我相信是 Object.is)。

【讨论】:

  • 谢谢,这是我一直在寻找的答案。如果我有声望,我会投票。
  • 如果您觉得这个答案很好地回答了您的问题,您应该能够接受。 stackoverflow.com/help/someone-answers
【解决方案2】:

咆哮你的组件。

变化:

  • initialState 移出UseEffectHook。你不需要创建 initialState 每次重新渲染;
  • 使用useCallback 将返回回调的记忆版本,仅当其中一个依赖项发生更改时才会更改;
  • setUsersetCountupdater function;
  • handleOnChangeUser 能够用于用户对象的所有字段。每次 handleOnChangeUser - 为用户对象创建新的引用。在这种情况下 useEffect 能够检测到变化;

import React, { useCallback, useEffect, useState } from 'react';

const initialState = {
  firstName: "Joe",
  lastName: "Smith",
  address: {
    home: "123 street",
  }
};

export function UseEffectHook() {
  const [user, setUser] = useState(initialState);
  const [count, setCount] = useState(0);
  const handleOnChangeUser = useCallback((event) => {
    const { name, value } = event;
    
    setUser(prevState => ({ ...prevState, [name]: value }));
  }, []);
  
  const increaseCount = useCallback(() => {
    setCount(prevState => prevState + 1);
  }, []);

  useEffect(() => {
    console.log("triggered");
  }, [user]);

  return (
    <div>
      <p>useEffect - Practice with different deps</p>
      {JSON.stringify(user)}

      <label>
        <span>Firstname:</span>

        <input
          type="text"
          name="firstName"
          onChange={handleOnChangeUser}
        />
      </label>
      
      <br />
      
      <label>
        <span>Lastname:</span>
        
        <input
          type="text"
          name="lastName"
          onChange={handleOnChangeUser}
        />
      </label>

      <button onClick={increaseCount}>Increase</button>
   </div>
  );
}

【讨论】:

    【解决方案3】:

    根据您的示例,只要您单击按钮,它就不会调用 useEffect() 。 否则,只要您通过输入字段更改用户名,就会调用 useEffect()。 (也就是说,useEffect() 将通过更改用户值来调用)

    useEffect(() => {
      console.log("invoke");
    }, [user]);
    

    为了在你点击按钮时调用useEffect(),它应该是这样的。

    useEffect(() => {
      console.log("invoke");
    }, [count]);
    

    【讨论】:

      猜你喜欢
      • 2022-01-11
      • 2019-08-09
      • 2021-10-11
      • 2021-09-29
      • 2019-11-20
      • 2020-04-29
      • 1970-01-01
      • 2022-06-12
      • 2021-08-31
      相关资源
      最近更新 更多