Search code examples
reactjsformsreact-hooksmodal-dialoguse-ref

How can I avoid re-render when props change in a modal in React?


I have a problem. I want to put a form inside a modal in react, and when the user click the button accept submit the data to a given url. But I want the modal be generic enough to wrap many forms but doing this the modal have to receive some parameters and every time the parameters change, the modal re-renders.

I create a custom hooks where I return the form and the data I extract from the form. Then I pass the form as a child of the modal component and the data as prop. Then when the user clic the accept button, the data will submit to the url.

But the form every time I write in it, re-render the modal. I can put the modal code inside every form component and it will work, but it's an ugly solution, the code won't be clean and won't be as efficient as it can. Hope you can help me.

The Modal Code:

`

const ModalDialogForm = (props) => {
    const { title = "Modal", isFullScreen = true, open, setOpen, children = "", cleanElements = () => { }, data = "", content } = props;

    const Transition = React.forwardRef(function Transition(props, ref) {
        return <Slide direction="up" ref={ref} {...props} />;
    });

    const cleanForm = () => {
        document.getElementById("modal-form").reset();
    }

    return (
        <>
            <Dialog fullScreen={isFullScreen} open={open} TransitionComponent={Transition} style={{
                color: "transparent",
                display: "flex", margin: "auto",
                justifyContent: "center", flexDirection: "column", borderRadius: "10px"
            }}>
                <AppBar sx={{ position: 'relative' }} style={{ backgroundColor: "white" }} elevation={0}>
                    <Toolbar variant='regular'>
                        <Typography sx={{ ml: 2, flex: 1 }} variant="h6" component="div" style={{ color: "black" }} >
                            {title}
                        </Typography>
                        <IconButton edge="start" color="inherit" onClick={() => setOpen(false)} aria-label="close">
                            <CancelIcon style={{ color: "black" }} />
                        </IconButton>
                    </Toolbar>
                </AppBar>
                <Paper style={{ backgroundColor: "rgb(249, 249, 249)", height: "100%", borderRadius: "0px" }} elevation={1}>
                    <form id="modal-form">
                        {children}
                        {content ? content() : ""}
                    </form>
                </Paper>
                <AppBar sx={{ position: 'relative' }} style={{ backgroundColor: "white" }} elevation={0}>
                    <Toolbar style={{ display: "flex", justifyContent: "flex-end" }}>
                        <Button style={{ backgroundColor: "green", color: "white" }} onClick={() => { console.log(data); }}>
                            Aceptar
                        </Button>
                        <Button style={{ color: "black" }} onClick={() => { cleanForm(); cleanElements(); }}>
                            Limpiar
                        </Button>
                        <Button style={{ color: "black" }} onClick={() => setOpen(false)}>
                            Cerrar
                        </Button>
                    </Toolbar>
                </AppBar>
            </Dialog>
        </>
    )
}

`

The Page where I call the modal:

`

    const renderModal = () => (
        <>
            <ModalDialogForm isFullScreen={false} title="Adicionar Idioma" open={modalOpened} setOpen={setModalOpened} data={data}>
                {getForm()}
            </ModalDialogForm>
        </>
    )

    useEffect(() => {
        setModal(
            modalOpened ? (<>
                {renderModal()}
            </>
            ) : (
                <></>
            )
        );
    }, [modalOpened, data]);

    return (
        <div>
            <IdiomaTable canInsert={insertar} canModify={modificar} canDelete={eliminar} openModal={() => { setModalOpened(true); }} />
            {modal}
        </div>
    )

`


Solution

  • I solve the problem. It is a temporary solution until I find a better one but works. Just removed the transition property of the Dialog component then the modal re-render but because don't have the transition the UI looks good. It is less fancy, but functional.