从父级关闭所有子模式

问题描述 投票:0回答:1

我具有以下树的三个组成部分:

<Update>
  <ExpenseItem>
    <ExpenseItemModal>

更新将花费一系列费用,并为每个费用呈现一个ExpenseItem组件。我正在使用一个钩子来处理模式可见性。如您所料,我正在使用此模式来编辑费用属性。

从ExpenseItem上的useModal挂钩导入切换方法以打开和关闭模式。我期望的是单击模式外部并关闭它。但是如果我将模式设置为true的另一个ExpenseItem,它将关闭当前窗口,但仍将显示另一个。我想在模态之外单击(也许在“更新”组件上)并立即关闭所有模态,以避免打开多个模态。其实我只想一次打开模式。

这些是以下组件:

上传

import { useState, useEffect } from 'react';
import useModal from '../hooks/useModal';
import ExpenseItem from './expenseItem';
import axios from 'axios';

function Update({ data }) {
    useEffect(() => console.log('update component', expenses));
    const saveToDatabase = () => {
        axios.post('http://localhost:3001/expenses', expenses).then((res) => {
            console.log('data is saved to database');
        });
    };
    const { setIsShowing } = useModal();
    const closeModals = () => setIsShowing(false);
    const [ expenses, setExpenses ] = useState(data);
    return (
        <div>
            {expenses.map((expense, index) => {
                return <ExpenseItem key={index} index={index} expenses={expenses} setExpenses={setExpenses} />;
            })}
            <button onClick={() => saveToDatabase()}>Save</button>
        </div>
    );
}

export default Update;

ExpenseItem

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;

EditExpenseModal

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;

useModal挂钩

import { useState } from 'react';

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

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

    return {
        isShowing,
        setIsShowing,
        toggle
    };
};

export default useModal;

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

javascript reactjs modal-dialog next.js
1个回答
0
投票
function hideModal() { setIsShowing(false); }
© www.soinside.com 2019 - 2024. All rights reserved.