Search code examples
javascriptreactjsreact-hooksreact-modal

React: Trigger a function from React Modal component


UPDATE: Code Sandbox link - https://codesandbox.io/s/goofy-dubinsky-4ui5v?file=/src/SearchRow.js

There is a use-case where we have a search results table and there are some rows that have a button to audit that row data for business purposes. Now when the user clicks on that button we need to prompt the user for confirmation and we are stuck on how to trigger this.

WHAT TO DO IN TODO PART (SearchRow.js)?

Here is the main SearchResultsPage.js

return (
  {results.map((searchRow) => {
    <SearchRow content={searchRow.content} showSaveButton={searchRow.content.id === 10} />
  });
);

SearchRow.js

function SearchRow({content, showSaveButton}) {
  const getConfirmation = (event) => {
     // TODO: Call Modal.js, if user presses yes then call the saveProductData function, otherwise return
  }

  const saveProductData = async () => {
    await axios.post("url", content);
  }

  <div>
    <p>{content.title}</p>
    {showSaveButton && 
      <Button variant="primary" onClick={(e) => getConfirmation(e)} />
    }
  </div>
}

Finally Modal.js

function Modal({
  heading,
  message,
  buttonSuccess = "Yes",    
  buttonFailure = "No",
  showModal = false,
}) {
  const [show, setShow] = useState(showModal);

  return (
    <BootstrapModal show={show} onHide={setShow(false)}>
      <BootstrapModal.Header closeButton>
        <BootstrapModal.Title>{heading}</BootstrapModal.Title>
      </BootstrapModal.Header>
      <BootstrapModal.Body>{message}</BootstrapModal.Body>
        <BootstrapModal.Footer>
          <Button variant="secondary" onClick={setShow(false)}>
            {buttonSuccess}
          </Button>
          <Button variant="primary" onClick={setShow(false)}>
            {buttonFailure}
          </Button>
       </BootstrapModal.Footer>
    </BootstrapModal>
  );
}

Can someone please help on how to achieve this or if there is any other better approach or any suggestions?

Thanks in advance :)


Solution

  • As far as I can understand, you want to render the modal only once the button is clicked, while that's quite natural for non-react environments, in react it works in a different way. In the simplest solution the Modal should be always rendered, and when a user clicks the button you change the modal open property to true.

    So, you can move logic that shows and hides modal from Modal.js to SearchRow.js, and then when user clicks showSaveButton button you can set showModal to true, and in return method check if that variable is truthy, if it is,than display modal, otherwise return null. Second, you pass two functions as props: First one will be executed if "YES" button on modal is pressed, second one will be excuted if "NO" button is pressed.

    Here is your modifed code :

    SearchRow.js

    function SearchRow({content, showSaveButton}) {
    
      const [showModal,setShowModal] = useState(false);
      
      const displayConfimationModal = (event) => {
         setShowModal(true);
      }
      
      const handleConfirmation = (event) => {
        console.log("confirmed");
        await saveProductData();
        setShowModal(false);
      }
      
      const handleDecline = (event) =>{
        console.log("declined");
        setShowModal(false);
      }
    
      const saveProductData = async () => {
        await axios.post("url", content);
      }
      
    return (
      <div>
        <p>{content.title}</p>
        {showSaveButton && 
          <Button variant="primary" onClick={(e) => displayConfimationModal(e)} />
        }
         {showModal ? ( < Modal onConfirm = {handleConfirmation}  onDecline={handleDecline}/>) : null}
      </div>);
    }
    

    Modal.js

    function Modal({
      heading="Default heading",
      message="Default message",
      onConfirm,
      onDecline,
      buttonSuccess = "Yes",    
      buttonFailure = "No",
    }) {
      
    
      return (
        <BootstrapModal>
          <BootstrapModal.Header closeButton>
            <BootstrapModal.Title>{heading}</BootstrapModal.Title>
          </BootstrapModal.Header>
          <BootstrapModal.Body>{message}</BootstrapModal.Body>
            <BootstrapModal.Footer>
              <Button variant="secondary" onClick={onConfirm}>
                {buttonSuccess}
              </Button>
              <Button variant="primary" onClick={onDecline}>
                {buttonFailure}
              </Button>
           </BootstrapModal.Footer>
        </BootstrapModal>
      );
    }
    
    export default Modal;