skip to Main Content

I want to invoke a function from one component to another component to open a element, it’s working fine but fires only once, can anyone please help me to get this working.
Component One should open whenever clicked on openmodal button even for n number of times.

function App() {
  let [modal, setModal]= useState(false)
  return (
    <div className="App">                      
          <div>
              <One modal={modal}/>
              <Two onModal={setModal}/>
          </div>
    </div>
  )
}
export function One({modal}) {
  let [open, setOpen] = useState(false)
  useEffect(() => {
    setOpen(modal)
  }, [modal])

  const openModal = () => {
    setOpen(true)
  }
  const closeModal = () => {
    setOpen(false)
  }
  return (
  <> 
    <div>
      <button onClick={openModal}>Create</button>
      {open && <div>MODAL WINDOW<br /><br /><br /><span onClick={closeModal}>CLOSE</span></div>}
    </div>   
  </>
  )
}
export function Two({onModal}) {
  return (
  <> 
    <div>
      <button onClick={() => onModal(true)}>Open Modal</button>
    </div>   
  </>
  )
}

I appreciate your response on this query

2

Answers


  1. There are 2 flags that determines whether component <One /> will show up or not —

    1. open in <One />
    2. modal in <App />

    When you open the model, both open and modal are set to true (due to setState and setState in useEffect).

    However, once you "CLOSE" it with the onClick event in <One />, despite open is set to false, the modal is still true.

    Why does that matter you might ask? Remember the dependency you have added in the useEffect block, the code inside it only updates when React detects a dependency has been updated. In this case, since modal remains true after we clicked "CLOSE", the setState inside it will never be trigger. Worse, even if it does, the modal will still go from true to true.

    The fix to it is to either pass the setModal component <One /> and add setModal(false) in the closeModal method. Or bubble the control of onClose to the <App />.

    Example —

    function App() {
      let [modal, setModal] = useState(false);
      return (
        <div className="App">
          <div>
            <One modal={modal} setModal={setModal} />
            <Two onModal={setModal} />
            {modal.toString()}
          </div>
        </div>
      );
    }
    
    function One({ modal, setModal }) {
      let [open, setOpen] = useState(false);
      useEffect(() => {
        setOpen(modal);
      }, [modal]);
    
      const openModal = () => {
        setOpen(true);
      };
      const closeModal = () => {
        setOpen(false);
        setModal(false);
      };
    
    Login or Signup to reply.
  2. Let us trace the flow:

    1. The three components are mounted – App, One and Two.
    2. On clicking the button “Open Modal”, the state modal in the component App changes to true.
    3. This state change causes another rendering of all three components.
      As a result, the component One reappears.
    4. Immediately the useEffect triggers in it.
    5. This causes a state change in component One.
    6. Please note this change is only in component One.
    7. The state open becomes true
    8. It triggers another render of One.
    9. Now One renders with the Modal Window since open is now true.
    10. It also causes the Close button visible in it.
    11. Now pressing the Close button, sets the state to false.
    12. It causes another render of One, and it results in closure of the modal.
    13. However, the state in the component App remains true.
    14. Now clicking the “Open Modal” button, does not change the state since the value already there and the new value – both are the same – true.
    15. Since there is no change in state in the component, App component does not re-render and the component One remains closed.
    16. This is the cause of the failure that the component One does not open again.

    A fix may be this:
    Add inverse data flow from the component One as well.
    This will keep the two states – open and modal in sync.

    Please see below the modified code and the results.

    App.js

    import { useState, useEffect } from 'react';
    
    function App() {
      let [modal, setModal] = useState(false);
      return (
        <div className="App">
          <div>
            <One modal={modal} onModal={setModal} />
            <Two onModal={setModal} />
          </div>
          modal in App : {modal.toString()}
        </div>
      );
    }
    
    function One({ modal, onModal }) {
      let [open, setOpen] = useState(false);
      useEffect(() => {
        setOpen(modal);
      }, [modal]);
    
      const openModal = () => {
        setOpen(true);
        onModal(true);
      };
      const closeModal = () => {
        setOpen(false);
        onModal(false);
      };
      return (
        <>
          <div>
            <button onClick={openModal}>Create</button>
            {open && (
              <div>
                MODAL WINDOW
                <br />
                <br />
                <br />
                <span onClick={closeModal}>CLOSE</span>
              </div>
            )}
          </div>
        </>
      );
    }
    
    export function Two({ onModal }) {
      return (
        <>
          <div>
            <button onClick={() => onModal(true)}>Open Modal</button>
          </div>
        </>
      );
    }
    
    export default App;
    

    Test results:

    1. Modal opened for the first time

    modal window opened for the first time

    1. Modal opened for the second time

    Modal opened for the second time

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search