You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React添加新日期后原有日期绑定的作业本地state被重置该如何解决

问题根因
  • 核心原因是列表渲染的key设置错误:你在DatesDisplay组件遍历日期数组时,直接用uuidv4()作为key值,每次dates数组更新触发组件重渲染时,所有日期项的key都会重新生成,React会判定所有旧的Date组件需要销毁并重新创建,每个Date组件内部存储作业数据的本地state自然会被清空。同理AssignmentDisplay组件遍历作业列表时也用了动态生成的uuid作为key,也存在作业状态丢失的隐患。
  • 次要隐患是作业数据存放在子组件本地state:如果后续组件结构调整、或者需要做数据持久化、跨组件操作作业数据,子组件本地state的灵活性会比较差。
解决方案

1. 快速修复(仅解决新增日期作业丢失问题)

直接将DatesDisplay组件的key替换为固定值,比如当前的日期字符串(保证日期不重复的前提下):

// DatesDisplay组件修改后代码
import React from 'react'
import Date from './Date';

const DatesDisplay = ({ dates }) => {
    return (
        <div className='assignment-display'>
            {dates.map((date) => {
                return (
                    <div key={date}>
                        <Date date={date}/>
                    </div>
                )
            })}
        </div>
    )
}
export default DatesDisplay

同时修改AssignmentDisplay的key,避免新增作业时旧作业状态异常,需要先调整作业提交逻辑,给每个作业生成固定id:
首先修改AssignmentInput的提交逻辑,导入uuid,给作业加id:

// AssignmentInput组件修改部分
import { v4 as uuidv4 } from 'uuid';
// ...其他代码不变
const submitNewAssignment = (e) => {
    e.preventDefault();
    addAssignment({
        ...assignment,
        id: uuidv4() // 新增唯一id
    });
    setAssignment({
        name: '',
        subject: '',
    });
}

然后修改AssignmentDisplay用作业id作为key:

// AssignmentDisplay组件修改后代码
import React from 'react'
import Assignment from './Assignment';

const AssignmentDisplay = ({ assignments }) => {
    return (
        <div>
            {assignments.map((assignment) => {
                return (
                    <div key={assignment.id}>
                        <Assignment name={assignment.name} subject={assignment.subject}/>
                    </div>
                )
            })}
        </div>
    )
}
export default AssignmentDisplay

2. 优化方案(状态提升,便于后续扩展)

如果后续需要实现作业删除、批量修改、数据持久化等功能,建议把所有数据提到顶层AssignmentCalendar组件统一管理,每个日期对象自带作业列表:
首先修改AssignmentCalendar组件:

import { useState } from 'react';
import { v4 as uuidv4 } from 'uuid';
import Button from './Button';
import DatesInput from './DatesInput';
import DatesDisplay from './DatesDisplay';

const AssignmentCalendar = () => {
    const [dates, setDates] = useState([]);
    
    const addDate = (dateStr) => {
        // 每个日期存储为带唯一id、日期字符串、作业列表的对象
        setDates(dates.concat({
            id: uuidv4(),
            dateStr: dateStr,
            assignments: []
        }))
    }

    // 新增修改指定日期作业的方法
    const updateAssignments = (dateId, newAssignment) => {
        setDates(dates.map(date => {
            if(date.id === dateId) {
                return {
                    ...date,
                    assignments: [...date.assignments, newAssignment]
                }
            }
            return date
        }))
    }
    

    return (
        <main className="main-display">
            <h3>Assignment Calendar</h3>
            <h4 className="dates-Title">Dates</h4>
            <Button 
                text='Add Date' 
                color='green'
            />
            <DatesInput dates={dates} addDate={addDate}/>
            <DatesDisplay dates={dates} updateAssignments={updateAssignments} />
        </main>
    )
}

export default AssignmentCalendar 

然后调整DatesDisplay传递参数:

const DatesDisplay = ({ dates, updateAssignments }) => {
    return (
        <div className='assignment-display'>
            {dates.map((date) => {
                return (
                    <div key={date.id}>
                        <Date 
                            date={date.dateStr}
                            dateId={date.id} 
                            assignments={date.assignments}
                            updateAssignments={updateAssignments}
                        />
                    </div>
                )
            })}
        </div>
    )
}

再修改Date组件,移除内部的作业state,用父组件传递的数据和方法:

import React from 'react';
import Assignments from './Assignments';
import Button from './Button';

const Date = ({ date, dateId, assignments, updateAssignments }) => {
    const addAssignment = (assignment) => {
        updateAssignments(dateId, assignment)
    }
    return (
        <div>
            <h5>{date} <Button text='Add Assignment'/></h5>
            <div className='assignment-display'>
                <Assignments assignments={assignments} addAssignment={addAssignment} />
            </div>
        </div>
    )
}

export default Date
关于localStorage的说明

你当前的问题属于代码逻辑bug,不需要用localStorage就能解决。只有你需要实现「关闭页面/刷新页面后,之前录入的日期和作业记录依然留存」的需求时,才需要用到localStorage:只需要在顶层AssignmentCalendar组件的dates状态更新时,将dates数组序列化后存入localStorage,组件初始化时从localStorage读取数据反序列化作为初始值即可。


内容的提问来源于stack exchange,提问作者amherro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 19:27:03