React Hooks "useState/useEffect/useCallback" 被有条件地调用

React Hooks "useState/useEffect/useCallback" are called conditionally

请告诉我我需要在哪里放置 list.length 条件 来移除 React Hooks are called conditionally 错误 ?我试图将它包装在 useEffect 中,但在这种情况下,在第一次渲染时会返回一个空列表。 重要 在第一次渲染时返回列表的方式与下面代码中的逻辑相同。

const List = ({ list }) => {
  if (list.length === 0) {
    return <div>LOADING...</div>;
  }

  const [localList, setLocalList] = useState(list);

  useEffect(() => {
    setList(localList);
  }, [localList]);

  const handleChange = useCallback((id) => {
    setLocalList((prevLocalList) =>
      prevLocalList.map((item, index) => {
        return index !== id ? item : { ...item, checked: !item.checked };
      })
    );
  }, []);

  return (
    <>
      {localList?.map((item, index) => (
        <MemoRow key={index} {...item} handleChange={handleChange} />
      ))}
    </>
  );
};

渲染结果在组件末尾返回,而不是在开头。使第一个操作成为整体 return 最后的一部分:

return (
  list.length === 0 ?
    <div>LOADING...</div> :
    <>
      {localList?.map((item, index) => (
        <MemoRow key={index} {...item} handleChange={handleChange} />
      ))}
    </>
);

此外,您的组件中存在逻辑问题。当父组件传递 list 值时,您将在该组件的本地状态中复制该值。如果父组件 更改 list 的值,该组件将 re-render 但 不会更新其本地状态

考虑到 UI 中的术语“正在加载...”,这意味着这正是此处发生的事情。所以在 re-render 上,list.length === 0 现在是 false,但是 localList 仍然是空的

作为“快速修复”,您可以随时更新 localList list 更改:

useEffect(() => {
  setLocalList(list);
}, [list, setLocalList]);

当然,如果父组件再次更改 list,这也会 over-write 对 localList 的任何本地更改。但是由于这是 重复状态 那么在这种情况下应该发生什么并不是很清楚。也许你只能在 localList 为空时有条件地更新它:

useEffect(() => {
  if (localList.length === 0) {
    setLocalList(list);
  }
}, [list, setLocalList, localList]);

这真的取决于你想如何处理这样的边缘情况。但最终,如果您希望这些更改反映在您的本地状态中,您将需要在 list 更改后更新 localList