0

I am trying to make a modal component which has a button within it that is supposed to close it:

import React, { useState } from "react";
import "./Modal.css";

interface modalProps {
    children?: React.ReactNode;
    width: string;
    height: string;
    screenFlood?: boolean; //Makes the rest of the screen go dark
    openModal: boolean;
}

const Modal = (props: modalProps) => {
    
    return props.openModal ? (
        <>
            {props.screenFlood && <div className="modal-screen-flood"></div>}
            <div
                className="modal-container"
                style={{ width: props.width, height: props.height }}
            >
                <div>Modal title</div>
                <div>{props.children}</div>
                <button
                    onClick={() => {
                        props.openModal = false;
                    }}
                >
                    Button
                </button>
            </div>
        </>
    ) : (
        <></>
    );
};

export default Modal;

The modal is opened from an external button here:

const [openModal, setOpenModal] = useState(false);

<Modal
    width="800px"
    height="400px"
    screenFlood={true}
    openModal={openModal}
>
    <div>Modal here</div>
</Modal>

How can I make the button inside the modal close the modal (I understand that props are readonly)

  • You cannot update props from inside a React Component. https://stackoverflow.com/questions/24939623/can-i-update-a-components-props-in-react-js – sean-7777 Aug 23 '22 at 22:53
  • yes you can @sean-7777 assuming you are passing the state setter from the parent to the child.... – Rob Terrell Aug 23 '22 at 23:22

3 Answers3

1

Add another prop called onClose, and pass it a function to change the value of openModal.

Your modal button becomes:

<button
    onClick={onClose}
>
    Close Modal
</button>

And your parent container becomes:

const [openModal, setOpenModal] = useState(false);
const handleClose = () => setOpenModal(false);

<Modal
    width="800px"
    height="400px"
    screenFlood={true}
    openModal={openModal}
    onClose={handleClose}
>
    <div>Modal here</div>
</Modal>
C. Helling
  • 1,394
  • 6
  • 20
  • 34
0

I once did a modal similar using functional components. Basically you can pass both the variable and the set function (setOpenModal) function to the modal as props and then use that setOpenmodal inside your modal component to change the state and close itself from within.

Something like this...

// Parent Component
const [openModal, setOpenModal] = useState(false);

<Modal
    width="800px"
    height="400px"
    screenFlood={true}
    openModal={openModal}
    setOpenModal={setOpenModal}
>
    <div>Modal here</div>
</Modal>




// Modal Component
const Modal = (props: modalProps) => {
    const { openModal, setOpenModal } = props
    return props.openModal ? (
        <>
            {props.screenFlood && <div className="modal-screen-flood"></div>}
            <div
                className="modal-container"
                style={{ width: props.width, height: props.height }}
            >
                <div>Modal title</div>
                <div>{props.children}</div>
                <button
                    onClick={() => {
                       setOpenModal(false);
                    }}
                >
                    Button
                </button>
            </div>
        </>
    ) : (
        <></>
    );
};

export default Modal;

Kushim
  • 303
  • 1
  • 7
0

Created new prop called closeModal with the type of the setter from use state:

interface modalProps {
    children?: React.ReactNode;
    width: string;
    height: string;
    screenFlood?: boolean; //Makes the rest of the screen go dark
    closeModal: React.Dispatch<React.SetStateAction<boolean>>;
}

In the parent container:

const [openModal, setOpenModal] = useState(false);

<button onClick={() => setOpenModal(true)}>
    Click me
</button>

{openModal && (
    <Modal
        width="800px"
        height="400px"
        screenFlood={true}
        closeModal={setOpenModal}
    >
        <div>Modal</div>
    </Modal>
)}

By moving the logic to open the modal outside into the parent, I could have the Modal and Parent share the state from the setter.