Search code examples
reactjsreact-nativecomponents

What might be causing a React Native component to continuously un- and re-mount?


I have a component that renders a child that when it's called from within another component, continuously unmount and remounts. I can't figure out why this is.

The code looks roughly like this:

import React, { useState } from 'react';
import { View } from 'react-native';
import EditLayout from './EditLayout'

export default users = (props) => {
    let { user } = props
    const [layout, setLayout] = useState([])
    const [layout, setLayout] = useState([])
    const Header = () => {
      return (<View>
                    <EditLayout layout={layout} user={user}  />
              </View>
      )
    }
    
    return (
      <View style={{ flex: 1 }}>
            {/* <EditLayout layout={layout} user={user}  /> */}
            <Header />
      </View>
    );
  }

And as-is this causes many re-renders of EditLayout (EditLayout is very minimal).

And when I swap the commented out code above where it says {/* <EditLayout ... /> /} to instead be {/ */}, then the remounts go away. It seems for some reason when called inside Header, it causes many un & remounts before finally settling down.

Any idea what may be causing this?

Edit: EditLayout and output

This is the relevant EditLayout code, even with just this below, I can replicate the issue (so it doesn’t have seem to have to do with the rest of the EditLayout code).

Here, I’m setting checkStateData to a default “Mounted Edit Layout” and changing it to false right away, only printing when it it’s true.

export default EditLayout = (props) => {
    const [checkStateData, setCheckStateData] = useState("Mounted Edit Layout")

    checkStateData && console.log("*****", checkStateData) // Print the current status 

    useEffect(() => {
      if(setCheckStateData){
        console.log("Made it here")
        setCheckStateData(false)
      }
    }, [])
    
    return (
      <View style={{ flex: 1 }}>
            {/* {headerLayoutData && headerLayoutData.map((card, i) => {
                          if (card && user){
                            return <Card card={card} key={i} user={user} />
                          }
                        })}
          {newCards && newCards.map((card, i) => {
              return <NewCard key={i} user={user} />
          })} */}
    
      </View>
    );
  }
Via <Header />

[Tue Feb 23 2021 15:43:11.836]  LOG      ***** Mounted Edit Layout
[Tue Feb 23 2021 15:43:11.853]  LOG      Made it here
[Tue Feb 23 2021 15:43:12.127]  LOG      ***** Mounted Edit Layout
[Tue Feb 23 2021 15:43:12.172]  LOG      Made it here
[Tue Feb 23 2021 15:43:12.179]  LOG      ***** Mounted Edit Layout
[Tue Feb 23 2021 15:43:12.259]  LOG      Made it here
[Tue Feb 23 2021 15:43:12.281]  LOG      ***** Mounted Edit Layout
[Tue Feb 23 2021 15:43:12.300]  LOG      Made it here
[Tue Feb 23 2021 15:43:12.303]  LOG      ***** Mounted Edit Layout
[Tue Feb 23 2021 15:43:12.307]  LOG      Made it here
[Tue Feb 23 2021 15:43:12.309]  LOG      ***** Mounted Edit Layout
[Tue Feb 23 2021 15:43:12.314]  LOG      Made it here
[Tue Feb 23 2021 15:43:12.364]  LOG      ***** Mounted Edit Layout
[Tue Feb 23 2021 15:43:12.373]  LOG      Made it here
[Tue Feb 23 2021 15:43:12.373]  LOG      ***** Mounted Edit Layout
[Tue Feb 23 2021 15:43:12.384]  LOG      Made it here


Without <Header>
[Tue Feb 23 2021 15:43:32.797]  LOG      ***** Mounted Edit Layout
[Tue Feb 23 2021 15:43:32.856]  LOG      Made it here

Solution

  • In your current code, Header (a component) is recreated each time Users component is rerendered. This will lead to bugs because you don't want to recreate a child component (instead it maybe rerendered when needed).

    And to prevent this, you should define Header outside parent component i.e. Users (Name should start with Upper Case).

    So, Header can be in a different file or in same file (but outside Users). If Header is going to be a large component, it is good to keep it in a different file.

    // Don't do this

    function MainComp() {
    
      //...
      function ChildComp() {
        // ... 
      }
    
    }
    

    // Do this instead

    function MainComp() {
      // ... 
    }
    
    function ChildComp() {
      // ... 
    }