I get the following error: React Error: "Rendered more hooks than during the previous render"
, and it is because inside a mapped array that I render are buttons that have their own useState hooks.
So I have an array of projects that I render from a list. Initially, only 3 projects are shown, and clicking a button will load the whole list.
The problem is that inside project can be multiple ProjectButtons, and those ProjectButtons are components because I want to use special hover states using the useState hook.
But when I change the size of the project list being rendered, it throws an error because of the useState hook inside the ProjectButton component.
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>
));
}
CodePudding user response:
You've defined ProjectButton
within your Projects
component, so you're breaking the rule of hooks - specifically "Only Call Hooks at the Top Level".
Move the ProjectButton
component out of the scope of Projects
and it will be happy.
CodePudding user response:
This is happening because you are using hooks inside a function and it should be used directly inside a component.
This can solved if you create ProjectButton
as a component instead of function.
Here is the updated code:
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>
));
}