在不更改数组的情况下,每个渲染中都会调用useEffect数组依赖项

时间:2020-05-16 15:26:32

标签: reactjs

import React, { useState, useEffect } from "react";

export default function App() {
  const [columns, setColumns] = useState([
    { name: "a" },
    { name: "b" },
    { name: "c" }
  ]);
  const [isOpen, setIsOpen] = useState(false);

  const addName = () => setColumns([...columns, { name: "r" }]);
  const toggleOpen = () => setIsOpen(!isOpen);

  return (
    <>
      <List columns={columns} />
      <button onClick={toggleOpen}>Toggle</button>
      <button onClick={addName}>Add</button>
      <p>{isOpen.toString()}</p>
    </>
  );
}

const List = ({ columns }) => {
  const names = columns.map(col => col.name);
  useEffect(() => {
    console.log("Names is changed to: ", names);
  }, [names]);

  return <p>{names.join(" ")}</p>;
};
Names is changed to:组件中更改isOpen状态时,将调用

App。 我希望仅在names数组更改时执行console.log。 我认为在List组件中,每当渲染时它都会创建一个新数组,以使先前的数组和新数组不相等。

2 个答案:

答案 0 :(得分:3)

should memoize the component,因此它将仅在道具更改时(或如果比较函数作为第二个参数传递时)呈现

当前,List的渲染是由于其父App渲染。

const List = ({ columns }) => {
  const names = columns.map((col) => col.name);
  useEffect(() => {
    console.log("Names is changed to: ", names);
  }, [names]);

  return <p>{names.join(" ")}</p>;
};

const MemoList = React.memo(List);

export default function App() {
  return (
    <>
      <MemoList columns={columns} />
    </>
  );
}

请参见工作示例:

Edit polished-pine-j17om


对于类组件,请使用React.PureComponent或实现shouldComponentUpdate

答案 1 :(得分:3)

const names = columns.map(col => col.name);

每次创建一个新数组,useEffect认为依赖关系已更改。

为避免这两种情况,请将names直接传递给useEffect

  useEffect(() => {
    console.log("Names is changed to: ", names);
  }, names);

或使用useMemo获得相同的数组对象:

const names = useMemo(() => columns.map(
   col => col.name
), [columns]);