Javascript 从父模式关闭所有子模式

Javascript 从父模式关闭所有子模式,javascript,reactjs,modal-dialog,next.js,Javascript,Reactjs,Modal Dialog,Next.js,我有三个具有以下树的组件: <Update> <ExpenseItem> <ExpenseItemModal> 我不介意更改这些模态结构以使其工作。在这种情况下,为了避免这些情况,您可以编写一个单独的方法来关闭模态 inside ExpenseItem.js <EditExpenseModal isShowing={isShowing} hide={hideModal} //

我有三个具有以下树的组件:

<Update>
  <ExpenseItem>
    <ExpenseItemModal>

我不介意更改这些模态结构以使其工作。

在这种情况下,为了避免这些情况,您可以编写一个单独的方法来关闭模态

inside ExpenseItem.js

<EditExpenseModal
                isShowing={isShowing}
                hide={hideModal}  //instead of toggle
                ...
 >
import useModal from '../hooks/useModal';
import EditExpenseModal from './editExpenseModal';

function ExpenseItem(props) {
    const { isShowing, toggle, setIsShowing } = useModal();
    let { description, date, credit, debit } = props.expenses[props.index];
    const updateValue = (expense, setExpenses, success) => {
        const expenses = [ ...props.expenses ];
        expenses.splice(props.index, 1, {
            ...expense
        });
        setExpenses(expenses);
        success();
    };
    return (
        <div>
            <div className="expense-box" onClick={toggle}>
                <p>{date}</p>
                <div className="expense-info">
                    <p className="expense-info--description">{description}</p>
                    <p className="expense-info--debit">{debit}</p>
                    <p className="expense-info--credit">{credit}</p>
                </div>
            </div>
            <EditExpenseModal
                isShowing={isShowing}
                hide={toggle}
                expense={props.expenses[props.index]}
                updateExpense={updateValue}
                setExpenses={props.setExpenses}
            />
            <style jsx>{`
                .expense-box {
                    width: 800px;
                    border: 1px solid black;
                    border-radius: 2px;
                    margin: 25px auto;
                    padding: 0 10px;
                }
                .expense-info {
                    display: flex;
                }
                .expense-info--description {
                    margin: 0 auto 0 0;
                }
                .expense-info--debit {
                    color: red;
                }
                .expense-info--credit {
                    color: green;
                }
            `}</style>
        </div>
    );
}

export default ExpenseItem;

import { useState, useEffect, Fragment } from 'react';
import { createPortal } from 'react-dom';

const EditExpenseModal = ({ expense, isShowing, hide, updateExpense, setExpenses }) => {
    const { description, date, credit, debit } = expense;
    useEffect(() => {
        document.body.style.overflow = 'hidden';
        return () => (document.body.style.overflow = 'unset');
    }, []);
    const [ expenseItem, setExpenseItem ] = useState({
        date,
        description,
        category: null,
        subcategory: null,
        credit,
        debit
    });
    const handleInputChange = (e) => {
        const { name, value } = e.target;
        setExpenseItem({ ...expenseItem, [name]: value });
    };
    return isShowing
        ? createPortal(
                <Fragment>
                    <div>
                        <div className="form">
                            <form>
                                <ul>
                                    <li className="form-inputs">
                                        <label>Date</label>
                                        <input type="text" name="date" defaultValue={date} onChange={handleInputChange} />
                                    </li>
                                    <li className="form-inputs">
                                        <label>Description</label>
                                        <input
                                            type="text"
                                            name="description"
                                            defaultValue={description}
                                            onChange={handleInputChange}
                                        />
                                    </li>
                                    <li className="form-inputs">
                                        <label>Category</label>
                                        <input type="text" name="category" onChange={handleInputChange} />
                                    </li>
                                    <li className="form-inputs">
                                        <label>Subcategory</label>
                                        <input type="text" name="subcategory" onChange={handleInputChange} />
                                    </li>
                                    <li className="form-inputs">
                                        <label>Credit</label>
                                        <input
                                            type="text"
                                            name="credit"
                                            defaultValue={credit}
                                            onChange={handleInputChange}
                                        />
                                    </li>
                                    <li className="form-inputs">
                                        <label>Debit</label>
                                        <input
                                            type="text"
                                            name="debit"
                                            defaultValue={debit}
                                            onChange={handleInputChange}
                                        />
                                    </li>
                                </ul>
                            </form>
                            <button onClick={() => updateExpense(expenseItem, setExpenses, hide)}>save</button>
                            <button onClick={hide}>close</button>
                        </div>
                        <style jsx>{`
                            .form {
                                background: grey;
                                display: flex;
                                flex-direction: column;
                                position: absolute;
                                height: 100vh;
                                top: 0;
                                right: 0;
                                width: 40%;
                            }
                            .form-inputs {
                                display: flex;
                                flex-direction: column;
                                list-style-type: none;
                                padding: 1rem 2rem;
                            }
                        `}</style>
                    </div>
                </Fragment>,
                document.body
            )
        : null;
};

export default EditExpenseModal;

import { useState } from 'react';

const useModal = () => {
    const [ isShowing, setIsShowing ] = useState(false);

    function toggle() {
        setIsShowing(!isShowing);
    }

    return {
        isShowing,
        setIsShowing,
        toggle
    };
};

export default useModal;

<EditExpenseModal
                isShowing={isShowing}
                hide={hideModal}  //instead of toggle
                ...
 >
function hideModal() {
        setIsShowing(false);
    }