skip to Main Content

Implemented a generic popup that is reusable in any component in my App by invoking it above the App component index.js:

const handleClickBtn = (confirmStatus,cancelStatus) => {
    console.log(`confirm: ${confirmStatus} ,cancel: ${cancelStatus}`);
}

root.render(
    <NavigationProvider>
        <PopupProvider onClickBtn={handleClickBtn}>
            <Provider store={store}>
                <App />
            </Provider>
        </PopupProvider>
    </NavigationProvider>
);

My Popup (Popup.js) is as follow:

import { createContext, useState } from 'react';

import Modal from 'react-bootstrap/Modal'
import Button from 'react-bootstrap/Button'

import ModalHeader from 'react-bootstrap/ModalHeader'
import ModalTitle from 'react-bootstrap/ModalTitle'
import ModalBody from 'react-bootstrap/ModalBody'
import ModalFooter from 'react-bootstrap/ModalFooter'

const PopupContext = createContext();

function PopupProvider({children,onClickBtn}) {

    const [show, setShow] = useState(false);
    const [showCancelButton, setShowCancelButton] = useState(true);
    const [size, setSize] = useState('md');
    const [message, setMessage] = useState('');
    const [title, setTitle] = useState('');
    const [confirm, setConfirm] = useState(false);
    const [confirmationText, setConfirmationText] = useState('Ok');
    const [cancel, setCancelation] = useState(false);
    const [cancelationText, setCancelationText] = useState('Close');

    const handleClose = () => {
        setShow(false);
    }

    const handleCancelation = () => {
        //setCancelation(true); //this state may not be needed
        setShow(false);
        onClickBtn(false,true);
    }

    const handleConfirmation = () => {
        //debugger;
        //setConfirm(true); //this state may not be needed
        setShow(false);
        onClickBtn(true,false);
    }


    const getConfStatus = () => {
        //return confirm;
    }

    const getCanStatus = () => {
        //return cancel;
    }


    const changeConfText = (btnText) => {
        setConfirmationText(btnText);
    }

    const changeCanText = (btnText) => {
        setCancelationText(btnText);
    }

    const showPopup = (showPopupL) => {
        setShow(showPopupL);
    }

    const popupSize = (size) => {
        setSize(size);
    }
    
    const popupMessage = (msg) => {
        setMessage(msg);
    }

    const popupTitle = (title) => {
        setTitle(title);
    }

    const popupCancelBtn = (showButton) => {
        setShowCancelButton(showButton);
    }

    const popupConfig = { 
        showPopup, 
        popupMessage, 
        popupSize, 
        popupTitle,
        popupCancelBtn,
        changeConfText,
        changeCanText,
        getConfStatus,
        getCanStatus 
    };

    return (
        <>
            <Modal 
                show={show}
                onHide={handleClose}
                size={size}
                aria-labelledby="contained-modal-title-vcenter"
                centered
                id="Popup"
            >
                <Modal.Header closeButton>
                {title !== '' ? <Modal.Title>{title}</Modal.Title> : ''}
                </Modal.Header>

                <Modal.Body>
                <p>{message}</p>
                </Modal.Body>

                <Modal.Footer>
                {showCancelButton ? 
                    <Button variant="secondary" onClick={handleCancelation}>
                        {cancelationText}
                    </Button>
                    :
                    ''
                }    
                <Button variant="primary" onClick={handleConfirmation}>
                    {confirmationText}
                </Button>
                </Modal.Footer>
            </Modal>
            <PopupContext.Provider value={popupConfig}>
                {children}
            </PopupContext.Provider>
        </>
    );

}

export { PopupProvider };
export default PopupContext;

and in any other Component just

import usePopup from '../hooks/use-popup';

const { 
    showPopup, 
    popupMessage,
    popupTitle,
    changeConfText,
    changeCanText,
    getConfStatus,
    getCanStatus
} = usePopup();

and use this functions to show or hide the Popup to change the text showed in the Popup the Buttons to show etc…

const DeleteConfirm = async () => {
    popupTitle(`Hike Deletion Confirmation`);
    popupMessage(`Are you shure you want to delete ${hike['hikeName']}`);
    changeConfText('Yes');
    changeCanText('Cancel');
    showPopup(true);
}

until here is works well my problem is now whant to trigger in this component the click event of the Popup to see if the user confirm’s for exemple the deletion of something and don’t know how to do that since using Context can only expose values and functions.

Should I use handleClickBtn in my top level but there can’t use state to pass down to child Components the state if the user clicked in Confirm button or not.

Any help is appreciated a bit lost at this point…

use-popup is the hook that exposes the useContext(PopupContext)

2

Answers


  1. Chosen as BEST ANSWER

    Just to make more clear the solution for me where @Anshu pointed in the right direction:

    In my Component:

    const HikeComp = () => {
        if(userConfirmation){
            const { 
                resetUserConfirmation
            } = popupConfig;
            DeleteHike();
            resetUserConfirmation();
        }
        ...
    }
    
    return (
        <>
            <Container>
                {HikeComp()}
            </Container>
        </>
    );
    

    So only needed to see the state userConfirmation and that would trigger the call to my function DeleteHike in this case and not try to make the trigger event propagate to this component that's where was complicating this process.


  2. Create a userConfirmation state in Popup.js

    Change the userConfirmation state according to ‘Cancel’ and ‘Confirm’ event.
    Pass it to PopupContext alongwith current popupConfig and fetch it in child component whose ancestor component is wrapped with PopupProvider.

    Popup.js

    const [userConfirmation, setUserConfirmation] = useState(null);
    
     const handleConfirmation = () => {
        setShow(false);
        setUserConfirmation(true);
        onClickBtn(true, false);
      };
    
      const handleCancelation = () => {
        setShow(false);
        setUserConfirmation(false);
        onClickBtn(false, true);
      };
    
    <PopupContext.Provider value={{ popupConfig, userConfirmation }}>
            {children}
     </PopupContext.Provider>
    

    Ancestor Component

    <PopupProvider onClickBtn={handleClickBtn}>
          <MyComponent />
    </PopupProvider>
    

    Child Component

    const { popupConfig, userConfirmation } = useContext(PopupContext);
    

    You can remove the handleClickBtn code.

    If you wanna play around with the code.

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