Search code examples
javascriptreactjstypescriptclonenext.js

Clone React JSX Element with nested state


I faced with some problem. I have heavy JSX Element with multipe states. In another part of app I need to pass this Element to Modal window with keeping all states. What is the best solution for solving this problem? Of course I can make Parent with all states and pass it to Child. But maybe it's possible to freeze all states and pass JSX Element as independent component?

Structure will look like:

ParentElement
|_
   AnotherElement
|_
   SomeHeavyElement

ParentElement:

const ParentElement= () => {
       return (
              <React.Fragment>
                  <AnotherElement />
                  <SomeHeavyElement />
              </React.Fragment>
       );
};
export default ParentElement;

AnotherElement:

const AnotherElement= () => {
       return (
              <React.Fragment>
                  <dialog>
                      <SomeHeavyElement/>
                  </dialog>
              </React.Fragment>
       );
};
export default AnotherElement;

SomeHeavyElement

const SomeHeavyElement= () => {
       const [state1, setState1] = useState(true);
       ...
       const [state99, setState99] = useState(false);

       return (
              <React.Fragment>
                 {/*some logic*/}
              </React.Fragment>
       );
};
export default SomeHeavyElement;

Solution

  • You have to lift state up, meaning you should define your state on top of both component (in <ParentElement>). You can't really freeze your component internal state.

    Here is a minimal example:

    const ParentElement= () => {
      const [state1, setState1] = useState(true); 
      // ...
      const [state99, setState99] = useState(false);
    
      return (
        <React.Fragment>
          <AnotherElement state={{state1, state99}} />
          <SomeHeavyElement state={{state1, state99}} />
        </React.Fragment>
      );
    };
    
    export default ParentElement;
    
    
    const SomeHeavyElement= ({state}) => {  
      return (
        <React.Fragment>
          {/*some logic*/}
        </React.Fragment> 
      );
    };
    export default SomeHeavyElement;
    
    const AnotherElement= ({state}) => {
      return (
        <React.Fragment>
          <dialog>
            <SomeHeavyElement state={state} />
          </dialog>
        </React.Fragment>
      );
    };
    
    export default AnotherElement;
    

    Also, when you have a lot of useState defined, you could useReducer to centralize your component state. Also, if you want to avoid props drilling, you could define handle your state using React API context.