Home > Enterprise >  How to not mount a component for every conditional rendering React
How to not mount a component for every conditional rendering React

Time:12-19

I have a conditional rendering where I render a Child component which have states. The case is that every time I render the Child component from Father component, the Child is mounted and it's state is reset. I don't want to reset the states inside, how can I do it?

const Father = () => {
  const [fatherState, setFatherState] = useState(false);
  
  return (
    {!fatherState ? <Child /> : <p>Hello</p>}
    
    <button onClick={() => setFatherState(!fatherState)}>Change father state</button>
    <p>Father state: {fatherState}</p>
  )
}

const Child = () => {
  const [childState, setChildState] = useState(0);
  
  return (
        <>
            <button onClick={() => setChildState(childState   1)}>Change child state</button>
            <p>Child state: {childState}</p>
        </>
    );
}

Any help is welcomed, thanks.

CodePudding user response:

To prevent the Child component from being mounted and its state from being reset every time the Father component is rendered, you can use the React.memo higher-order component. React.memo is a performance optimization that helps to avoid re-rendering a component if its props have not changed.

To use React.memo, you can wrap the Child component in a call to React.memo, like this:

const Child = React.memo(() => {
  const [childState, setChildState] = useState(0);

  return (
    <>
      <button onClick={() => setChildState(childState   1)}>Change child state</button>
      <p>Child state: {childState}</p>
    </>
  );
});

By default, React.memo compares the props of the wrapped component using a shallow equality check (using the Object.is function). This means that if the props are the same object, React.memo will consider them equal and avoid re-rendering the component.

You can also provide a custom comparison function as the second argument to React.memo if you need to use a different comparison algorithm. For example:

const arePropsEqual = (prevProps, nextProps) => {
  // Custom comparison logic goes here
  return true; // or false
};

const Child = React.memo(() => {
  // ...
}, arePropsEqual);

I hope this helps! Let me know if you have any questions.

CodePudding user response:

I don't think you can do it, because you are having a condition to render Child and whenever the condition is false Child will be unmounted and again mounted in condition true (so all Child states will be gone), so the only way might be just to define child states in parent component and pass to Child as props, or use state management like redux or context

CodePudding user response:

{!fatherState ? <Child /> : <p>Hello</p>} This is your problem, your adding and removing child, so of course state is lost. If you want to keep the state of Child, you could maybe set the component's display property to none instead.

Below is an example, where I pass a prop called vis, that makes the child visible..

const {useState} = React;

const Father = () => {
  const [fatherState, setFatherState] = useState(false);
  
  return (<React.Fragment>
    {!fatherState && <p>Hello</p>}
    <Child vis={fatherState}/>
    
    <button onClick={() => setFatherState(!fatherState)}>Change father state</button>
    <p>Father state: {fatherState}</p>
    </React.Fragment>
  )
}

const Child = ({vis}) => {
  const [childState, setChildState] = useState(0);
  
  return (
        <div style={{display: vis ? 'block' : 'none'}}>
            <button onClick={() => setChildState(childState   1)}>Change child state</button>
            <p>Child state: {childState}</p>
        </div>
    );
}


const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Father/>);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>

<div id="root"></div>

  • Related