useEffect和依赖项数组

时间:2020-04-26 17:21:49

标签: reactjs react-hooks

我试图了解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。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:2)

每当对象更改引用时,

useEffect将在其依赖项数组中重新运行该对象。

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

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

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

这都是关于引用相等的。每个渲染器上是否为previousUser === newUser。对于依赖数组中的每个变量,React本质上都执行与检查(我相信Object.is)非常相似的检查。

答案 1 :(得分:1)

使用您的组件。

更改:

  • 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>
  );
}