简体   繁体   English

反应异步计时问题,导致模式在 state 更改后弹出预填充表单?

[英]React async timing issue, cause modal to pop up with prefilled form after state change?

I have a setCurrentProject call using useState, useEffect hooks api but the modal pops up before the state has been set and it causes the data to throw an error or be blank if i throw in a conditional to check if it's there.我有一个使用 useState 的 setCurrentProject 调用,useEffect 挂钩 api 但模式在 state 设置之前弹出,如果我输入条件以检查它是否存在,它会导致数据抛出错误或为空白。

How do I make sure the state changes before the modal opens with the correct prop data如何确保 state 在使用正确的道具数据打开模态之前发生变化

const EditProjectModal = ({modalOpen, handleClose, addTask, currentProject}) => {
    const [name, setName] = useState("");
    const [startDate, setStartDate] = useState(null);
    const [endDate, setEndDate] = useState(null);
    const [projectTasks, setProjectTasks] = useState([]);

    useEffect(() => {
        setName(currentProject.name)
        setProjectTasks(currentProject.tasks)
        setStartDate(currentProject.startDate)
        setEndDate(currentProject.endDate)
    }, [currentProject])

    return(
        <Modal
        centered={false}
        open={modalOpen}
        onClose={handleClose}
        >
            <Modal.Header>Edit Project</Modal.Header>
            <Modal.Content>
                <Form onSubmit={handleSubmit}>
                    <Form.Group widths="equal">

                        <Form.Field
                            control={Input}
                            label="Project" 
                            placeholder="Enter the name of your project..."
                            required 
                            value={name}
                            onChange={handleName}
                        />
                    </Form.Group>

                    <Form.Group widths='equal'>

                        <Form.Field required>
                            <label>Start Date</label>
                            <DatePicker 
                                selected={startDate}
                                onChange={date => setStartDate(date)}
                                selectsStart
                                startDate={startDate}
                                endDate={endDate}
                            />
                        </Form.Field>

                        <Form.Field required>
                            <label>End Date</label>
                            <DatePicker 
                                selected={endDate}
                                onChange={date => setEndDate(date)}
                                selectsEnd
                                startDate={startDate}
                                endDate={endDate}
                                minDate={startDate}
                                placeholderText="Select end date.."
                            />
                        </Form.Field>

                    </Form.Group>

                    <ProjectTasksContainer projectTasks={projectTasks} setProjectTasks={setProjectTasks}/>

                    <Divider hidden/>

                    <Button type='submit'>Submit</Button>
                </Form>
            </Modal.Content>
        </Modal>

I've left out some of the change functions etc because that's not important to the state change.我省略了一些更改功能等,因为这对 state 更改并不重要。

It's being triggered by a button from another component它是由另一个组件的按钮触发的

const handleEdit = () => {
        setCurrentProject(project)
        handleEditProjClick();
    }

edited to add dashboard that uses the editProjectModal编辑以添加使用 editProjectModal 的仪表板

const Dashboard = ({notes, setNotes, tasks, setTasks, goals, setGoals, projects, setProjects}) => {
    //============== STATE VARIABLES ===================//
    const [projModalOpen, setProjModalOpen] = useState(false);
    const [editProjModalOpen, setEditProjModalOpen] = useState(false);
    const [currentProject, setCurrentProject] = useState({});

    //============== MODALS ===================//

    const handleProjModalOpen = () => {
        setProjModalOpen(true);
    }

    const handleProjModalClose = () => {
        setProjModalOpen(false);
    }

    const handleEditProjModalOpen = () => {
        setEditProjModalOpen(true);
    }

    const handleEditProjModalClose = () => {
        setEditProjModalOpen(false);
    }

    //============== RENDERING FUNCTION ===================//
    return (
        <Fragment>
                    <Grid columns={2}>
                        <Grid.Row stretched>

                            <Grid.Column width={12}>

                                <Container style={{width: "90%"}}>
                                    <Segment basic>
                                        <Segment textAlign="right">
                                            <ProjectButton handleClick={handleProjModalOpen}/>
                                            <ProjectModal handleClose={handleProjModalClose} modalOpen={projModalOpen} addTask={addTask} addProject={addProject} />
                                            <EditProjectModal handleClose={handleEditProjModalClose} modalOpen={editProjModalOpen} addTask={addTask} currentProject={currentProject} />
                                        </Segment>

                                </Container>

                            </Grid.Column>

                            <Grid.Column width={4}>
                                <Segment>
                                    <ProgressContainer projects={projects} handleProjClick={handleProjModalOpen} handleEditProjClick={handleEditProjModalOpen} setCurrentProject={setCurrentProject}/>
                                </Segment>
                            </Grid.Column>

                        </Grid.Row>
                    </Grid>
        </Fragment>
    )
}

the parent holds the setCurrentProject state and passes it down to that child and also passes down the handleEditProjClick();父级持有 setCurrentProject state 并将其向下传递给该子级,并向下传递 handleEditProjClick();

What's the best way to handle this issue?处理这个问题的最佳方法是什么?

Cheers!干杯!

Because editProjModalOpen and currentProject are independent you could get a situation where editProjModalOpen is true and currentProject is {} - you'd need to account for that, eg {.isEmpty(currentProject) && <EditProjectModal... /.>}因为editProjModalOpencurrentProject是独立的,您可能会遇到editProjModalOpentruecurrentProject{}的情况 - 您需要考虑这一点,例如{.isEmpty(currentProject) && <EditProjectModal... /.>}

This would then guarantee currentProject is set in EditProjectModal and you could just set the initial values in state off the currentProject :这将保证currentProjectEditProjectModal中设置,您可以在currentProject中设置 state 中的初始值:

const [name, setName] = useState(currentProject.name);
const [startDate, setStartDate] = useState(currentProject.startDate);

Or if you have to useEffect then just check the state before rendering the modal:或者,如果您必须使用useEffect ,则只需在呈现模态之前检查 state:

if (!name ) {
   return null
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM