为什么这会创建一个带有 React 钩子的无限渲染循环?

Why does this create an infinite render loop with React hooks?

我正在尝试将啤酒名称呈现为按字母排序的 H1 元素,我是 React Hooks 的新手,但这似乎会导致重新呈现循环

Beer 组件从使用 useEffect Hook 的 Home 组件传递了一系列啤酒作为道具,虽然我不确定,但我怀疑这可能是罪魁祸首。

const Beer = ({ beer }) => {
  const [beers, setBeers] = useState([]);
  let rendered;
  if (beer === undefined) {
    rendered = <Spinner />;
  } else {
    rendered = beer.map(beer => beer.name);
    setBeers(rendered.sort());
    rendered = beers.map(beer => <h1>{beer}</h1>);
  }

  return <div>{rendered}</div>;
};

const Home = () => {
  const [beers, setBeers] = useState();
  useEffect(() => {
    const getBeers = async () => {
      const beerData = await fetch('https://api.punkapi.com/v2/beers');
      const beers = await beerData.json();
      console.log(beers);
      setBeers(beers);
    };
    getBeers();
  }, []);

  return (
    <div>
      <h1>Punk Beers</h1>
      <Beer beer={beers} />
    </div>
  );
};

我希望有一个 H1 元素的渲染列表,但这会产生无限循环的渲染。

当您在 Beer 内部调用 setBeers 时,React 将 re-render 组件(即 re-execute 函数)为 [=13] 提供更新值=] 状态变量.

您通常不需要像这样将道具复制到状态中。如果你有一个组件在显示之前对 props 执行昂贵的操作,你可能想要 use memoization to cache the result.

在这种情况下,简单地排序 beers 并不昂贵,除非您的数组有成千上万的项目,所以不需要优化。

const Beer = ({ beers }) => (
  beers ? (
    [...beers].sort().map((beer, index) => 
      <h1 key={index}>{beer}</h1>
    )
  ) : (
    <Spinner />
  )
)

const Home = () => {
  const [beers, setBeers] = useState();
  useEffect(() => {
    const getBeers = async () => {
      const beerData = await fetch('https://api.punkapi.com/v2/beers');
      const beers = await beerData.json();
      console.log(beers);
      setBeers(beers);
    };
    getBeers();
  }, []);

  return (
    <div>
      <h1>Punk Beers</h1>
      <Beer beers={beers} />
    </div>
  );
};