Creating components inside components without memoization leads to unstable components. The nested component and all its children are recreated during each re-render. Given stateful children of the nested component will lose their state on each re-render.
React reconcilation performs element type comparison with reference equality. The reference to the same element changes on each re-render when defining components inside the render block. This leads to complete recreation of the current node and all its children. As a result the virtual DOM has to do extra unnecessary work and possible bugs are introduced.
The following patterns are considered warnings:
function Component() {
function UnstableNestedComponent() {
return <div />;
}
return (
<div>
<UnstableNestedComponent />
</div>
);
}
function SomeComponent({ footer: Footer }) {
return (
<div>
<Footer />
</div>
);
}
function Component() {
return (
<div>
<SomeComponent footer={() => <div />} />
</div>
);
}
class Component extends React.Component {
render() {
function UnstableNestedComponent() {
return <div />;
}
return (
<div>
<UnstableNestedComponent />
</div>
);
}
}
The following patterns are not considered warnings:
function OutsideDefinedComponent(props) {
return <div />;
}
function Component() {
return (
<div>
<OutsideDefinedComponent />
</div>
);
}
function Component() {
const MemoizedNestedComponent = React.useCallback(() => <div />, []);
return (
<div>
<MemoizedNestedComponent />
</div>
);
}
function Component() {
return (
<SomeComponent footer={<div />} />
)
}
By default component creation is allowed inside component props only if prop name starts with render
. See allowAsProps
option for disabling this limitation completely.
function SomeComponent(props) {
return <div>{props.renderFooter()}</div>;
}
function Component() {
return (
<div>
<SomeComponent renderFooter={() => <div />} />
</div>
);
}
...
"react/no-unstable-nested-components": [
"off" | "warn" | "error",
{ "allowAsProps": true | false }
]
...
You can allow component creation inside component props by setting allowAsProps
option to true. When using this option make sure you are calling the props in the receiving component and not using them as elements.
The following patterns are not considered warnings:
function SomeComponent(props) {
return <div>{props.footer()}</div>;
}
function Component() {
return (
<div>
<SomeComponent footer={() => <div />} />
</div>
);
}
If you are not interested in preventing bugs related to re-creation of the nested components or do not care about optimization of virtual DOM.