如何将 useEffect 挂钩与依赖列表一起用作对象数组中的特定字段?

How to use useEffect hook with the dependency list as a specific field in an array of objects?

假设我有一个这样的数组:

[
  {
    country: '',
    'city/province': '',
    street: ''
  },
  {
    country: '',
    'city/province': '',
    street: ''
  }
]

每次数组中任何项目中的 'country' 字段的值发生变化时,如何让 useEffect() 挂钩 运行?

我认为您不能在依赖项数组中专门解决它,但是,您可以在 useEffect 中进行检查以获得相同的总体结果。

基本上,依赖数组传递了完整的数据状态,这将在每次更改时触发效果,然后您进一步检查子属性是否已更改。

为简洁起见,我使用 lodash,但您可以 运行 任何函数来确定数据是否已更改。

代码笔:https://codepen.io/chrisk7777/pen/mdMvpvo?editors=0010

const { useState, useEffect, useRef } = React;
const { render } = ReactDOM;
const { isEqual, map } = _;

const App = () => {
  const [data, setData] = useState([
    {
      country: "",
      "city/province": "",
      street: ""
    },
    {
      country: "",
      "city/province": "",
      street: ""
    }
  ]);
  const prevData = useRef(data);

  // hacky updates just to demonstrate the change
  // change country - should trigger useEffect
  const update1 = () => {
    setData((s) => [s[0], { ...s[1], country: s[1].country + "a" }]);
  };

  // change street - should not trigger useEffect
  const update2 = () => {
    setData((s) => [s[0], { ...s[1], street: s[1].street + "a" }]);
  };

  useEffect(() => {
    if (!isEqual(map(prevData.current, "country"), map(data, "country"))) {
      console.log("country changed");
    }

    prevData.current = data;
  }, [data]);

  return (
    <div>
      <button onClick={update1}>change country - trigger effect</button>
      <br />
      <button onClick={update2}>change street - do not trigger effect</button>
    </div>
  );
};

render(<App />, document.getElementById("app"));

只需将国家映射到效果依赖数组即可。

const countries = data.map((x) => x.country);

useEffect(() => {
  console.log(countries);
}, countries);

通常你不想这样做,但只是为了回答你的问题,这是可以做到的,所以让我提出以下建议,假设你的列表被称为 items:

  useEffect(() => {
    
  }, [...items.map(v => v.country)])

上面的代码所做的是将所有 items(及其 country 属性)散布到 useEffect 依赖数组中。

之所以这可以是临时的,主要是因为React不喜欢有可变长度的依赖。在源代码中,当长度发生变化时,它只欣赏现有元素的元素变化。因此,如果您从 1 个元素切换到 2 个元素,您可能 运行 会遇到问题。

但是,如果您有固定数量的元素,这应该可以满足您的要求。请记住 items 必须始终是一个数组。

注意:为了解决长度问题,也许我们可以向依赖数组添加一个额外的变量 length :)

  }, [items.length, ...items.map(v => v.country)])

正如我提到的,大多数情况下,您应该避免这样做,而是每次更改项目时都尝试更改整个 items。并让Item显示优化,如React.memo.