Do not define components during render

I just ran into an interesting SonarLint problem. “Do not define components during render”

Do not define components during render. React will see a new component type on every render and destroy the entire subtree\u8217s DOM nodes and state. Instead, move this component definition out of the parent component \u8220App\u8221 and pass data as props. If you want to allow component creation in props, set allowAsProps option to true.sonarlint(javascript:S6478)

This popped up when I was following the document to customise an authentication component in Amplify UI. In particular, this document.

The Problem Code

My code contained a functional component named App. Inside App I created the components object. Inside the return method I used the components object as a prop to an Authenticator component.

function App({ signOut, user }) {
    const navigate = useNavigate();
    const components = {
        Header() {
            return (
            <Flex direction="row" justifyContent="center">
                <Image
                    id="logo"
                    width="auto"
                    height="90px"
                    shrink="0"
                    position="relative"
                    padding="0px 0px 15px 0px"
                    src={logo}
                />
            </Flex>)
        }
    }

    return (
        <div>
            <Authenticator components={components}>

The issue was with the header component being created within the components object. Each time the Appcomponent was created, a new header component would be created. Following the tip in the warning messsage I was able to fix the issue by moving the components object outside of the App component.

The Solution Code

const components = {
    Header() {
        return (
        <Flex direction="row" justifyContent="center">
            <Image
                id="logo"
                width="auto"
                height="90px"
                shrink="0"
                position="relative"
                padding="0px 0px 15px 0px"
                src={logo}
            />
        </Flex>)
    }
}

function App({ signOut, user }) {
    const navigate = useNavigate();
    
    return (
        <div>
            <Authenticator components={components}>

The components object is now being created outside of the App component. With this, the sonar lint message “Do not define components during render” has disappeared. Also, the components object won’t be recreated each time App rerenders.

This results in a performance boost and stability to the app. This can also serve as a warning for blindly following tutorials (mine included).

Don’t forget to check out my React page here which contains links to common concepts and examples in React.

Also, you can follow me on Twitter/X here! And now, mastodon: @bernieslearnings@mastodon.social

Leave a Reply

Your email address will not be published. Required fields are marked *