I know this error has been seen many times:
Rendered more hooks than during the previous render.
From what I read, it’s to do with an early return statement. Well I’m creating a library for our company where I wrap a form and allow them to pass their own layout. Initially the form isn’t ready to render their form (depending on a few factors), but eventually it’s ready and should render. That creates a conditional render, and returns me that error.
What I don’t understand is if I explicitly check a boolean value to determine if it’s ready, I am not rendering anything where there will be an invalid number of hooks.
I’ve created a simplified example of the problem/error below. Here I check if it’s "ready" (yes, I’m just doing this in a useEffect but it’s more complicated than this, but the result is the same). I then conditionally check if we’re ready to render their layout (which may or may not contain hooks – which gives the error), or I’d like to return a default component message.
From reading I MUST render this dynamic component regardless or look to pass a prop down to the child, so the consumer has to check if it’s ready to then do their layout – and that’s nasty.
Is this really the case or am I missing something simple? Can I disable the error knowing myself it’s impossible for it until a certain state is ready?
This will produce the error:
export function ParentComponent({childComponent}) {
const [ready, setReady] = useState(false);
useEffect(() => {
console.log("Mounted, now ready");
setReady(true);
}, []);
if (ready)
// This is what a user passes, so can be any component which can use hooks, as per my example
return childComponent();
return <p>Not ready yet.</p>
}
export function childComponent() {
// Important, this breaks it
const [someStateValue, setSomeStateValue] = useState(false);
return <p>Hello: {someStateValue}</p>;
}
Usage:
return <ParentComponent childComponent={childComponent}></ParentComponent>
2
Answers
Yes. If
childComponent
is a component, you should render it like a component. That way, any hooks that thechildComponent
function calls will be associated with that as a separate component instead of being associated with your parent component. By calling it like a normal function, React doesn’t have a way to tell that the hooks from the child are not supposed to be "part of" your component.Note the
childComponent: ChildComponent
that I changed from your original post. I’m not 100% sure offhand, but I think this will be necessary so that React doesn’t try to do e.g. adocument.createElement('childComponent')
. You’d still use the prop as<ParentComponent childComponent={childComponent} />
When you call a component as a normal function
myComponent()
it is not the same to React as using it as JSX (orReact.createElement(myComponent)
). Without this, the component will not get it’s own component lifecycle (mount, unmount, etc) and you cannot use hooks reliably.You can change it to use JSX and capitalize the component name to allow hooks to be used: