更改渲染数组大小时反应挂钩错误

React hook error when changing size of rendered array

我收到以下错误:React Error: "Rendered more hooks than during the previous render",这是因为在我呈现的映射数组中是具有自己的 useState 挂钩的按钮。

所以我有一组从列表中呈现的项目。最初只显示 3 个项目,单击一个按钮将加载整个列表。

问题是项目内部可以有多个 ProjectButton,而这些 ProjectButton 是组件,因为我想使用 useState 挂钩来使用特殊的悬停状态。

但是当我更改正在呈现的项目列表的大小时,由于 ProjectButton 组件中的 useState 挂钩,它会抛出错误。

import { projects } from "../lib/projectList";

const Projects: FC = () => {
    // Initially use a portion of the array
    const [projectArray, setProjectArray] = useState(projects.slice(0, 3));

    // Load the whole array on button click
    const loadMoreProjects = () => {
        setProjectArray([...projects]);
    }

    const ProjectButton = (button: { type: string, link: string }) => {
        // Removing this useState hook fixes the problem, but I need it for my design
        const [hoverColor, setHoverColor] = useState("#0327d8");

        const handleMouseEnter = () => {
            setHoverColor("white");
        }
        const handleMouseLeave = () => {
            setHoverColor(original);
        }

        return (
            <a href={button.link} rel="noreferrer" target="_blank" key={button.link}>
                <button onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
                    <WebsiteIcon className="projectButtonIcon" fill={hoverColor} />
                    <p>{button.type}</p>
                </button>
            </a>
        );
    }

    return projectArray.map(project => (
        ...
        <div className="projectLinks">
            {project.buttons.map(button => ProjectButton(button))}
        </div>
        ...
        <Button onClick={loadMoreProjects}>Load More</Button>
    ));
}

您在 Projects 组件中定义了 ProjectButton,因此您违反了钩子规则 - 特别是“Only Call Hooks at the Top Level”。

ProjectButton 组件移出 Projects 的范围,它会很高兴。

发生这种情况是因为您在函数内部使用了钩子,它应该直接在组件内部使用。 如果您将 ProjectButton 创建为组件而不是函数,则可以解决此问题。

这是更新后的代码:

import { projects } from "../lib/projectList";



const ProjectButton = (button) => {
  // Removing this useState hook fixes the problem, but I need it for my design
  const [hoverColor, setHoverColor] = useState("#0327d8");

  const handleMouseEnter = () => {
    setHoverColor("white");
  };
  const handleMouseLeave = () => {
    setHoverColor(original);
  };

  return (
    <a href={button.link} rel="noreferrer" target="_blank" key={button.link}>
      <button onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
        <WebsiteIcon className="projectButtonIcon" fill={hoverColor} />
        <p>{button.type}</p>
      </button>
    </a>
  );
};

const Projects: FC = () => {
    // Initially use a portion of the array
    const [projectArray, setProjectArray] = useState(projects.slice(0, 3));

    // Load the whole array on button click
    const loadMoreProjects = () => {
        setProjectArray([...projects]);
    }

    return projectArray.map(project => (
        ...
        <div className="projectLinks">
            {project.buttons.map((button) => (
              <ProjectButton {...button} />
             ))}
        </div>
        ...
        <Button onClick={loadMoreProjects}>Load More</Button>
    ));
}