Given this minimal example:
import React, { useState } from 'react';
function Component({ num }) {
const [lorem, setLorem] = useState('lorem');
return (
<div>
{num}: {lorem}
</div>
);
}
function AnotherComponent({ render = Component }) {
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<button type="button" onClick={() => setIsOpen(true)}>
Open
</button>
{isOpen ? render({ num: 123 }) : null}
</div>
);
}
When running a unit test that clicks the button I get the error Rendered more hooks than during the previous render..
The error kind of makes sense – on one render the useState('lorem') isn’t in the document, then when the button is clicked, it is. However, this error does not occur when I define the Component using JSX (i.e. {isOpen ? <Component num={123} /> : null} but it does when I try to use the render prop.
Is there a way to use the render prop pattern like this and avoid the hooks error?
>Solution :
As you noted, you need to use render as a JSX tag, otherwise the hook calls within render aren’t considered as part of a separate component, but rather as part of AnotherComponent. In React, JSX tags that aren’t inbuilt must start with a capitalized letter, so you can alias the destructured render prop to be Render, and then use it as a component:
function AnotherComponent({ render: Render = Component }) { // alias the render prop
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<button type="button" onClick={() => setIsOpen(true)}>
Open
</button>
{isOpen ? <Render num={123} /> : null}
</div>
);
}