在 React 中添加新项目后,本地状态会重置

Local state gets reset after adding a new item in React

我正在制作一个小型 React 应用程序来跟踪家庭作业。您应该能够添加多个日期,并在这些日期内添加多个作业。我可以将日期打印到屏幕上,也可以打印出一天的多个作业。然而,在添加另一个日期后,存储所有先前日期分配的本地状态将被清除,因此每个日期的分配都会消失。所有日期仍显示在屏幕上,但其中的分配不再存在,也不再处于状态。添加新日期时,如何让分配保留在屏幕上并处于状态?这是我需要本地存储的东西吗?如果能得到任何帮助,我将不胜感激。下面是我的代码:

import Button from './Button';
import DatesInput from './DatesInput';
import DatesDisplay from './DatesDisplay';

const AssignmentCalendar = () => {
    const [dates, setDates] = useState([]);
    
    const addDate = (date) => {
        setDates(dates.concat(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} />
        </main>
    )
}

export default AssignmentCalendar 
import React, { useState } from 'react'
import Button from './Button'

const DatesInput = ({ addDate }) => {
    const [ date, setDate ] = useState('')
    
    const typeInDate = (e) => {
        setDate(e.target.value)
    }

    const submitDate = (e) => {
        e.preventDefault();
        addDate(date)
        setDate('')
    }

    return (
        <form className='dates-input' onSubmit={submitDate}>
            <label className='input-label'>Please enter a new date...</label>
            <input type='text' value={date} onChange={typeInDate} ></input>
            <Button text='Submit' />
        </form>
    )
}

export default DatesInput
import React from 'react'
import Date from './Date';
import { v4 as uuidv4 } from 'uuid';


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

export default DatesDisplay

import React, { useState } from 'react';
import Assignments from './Assignments';
import Button from './Button';

const Date = ({ date }) => {
    const [assignments, setAssignments] = useState([]);

    const addAssignment = (assignment) => {
        setAssignments(assignments.concat(assignment))
    }
    return (
        <div>
            <h5>{date} <Button text='Add Assignment'/></h5>
            <div className='assignment-display'>
                <Assignments assignments={assignments} addAssignment={addAssignment} />
            </div>
        </div>
    )
}

export default Date
import React from 'react'
import AssignmentInput from './AssignmentInput';
import AssignmentDisplay from './AssignmentDisplay';

const Assignments = ({ assignments, addAssignment }) => {
    return (
        <div>
            <AssignmentInput addAssignment={addAssignment} />
            <AssignmentDisplay assignments={assignments} />
        </div>
    )
}
export default Assignments
import React, { useState } from 'react'
import Button from './Button';

const AssignmentInput = ({ addAssignment }) => {
    const [assignment, setAssignment] = useState({
        name: '',
        subject: '',
    });
    const handleAddName = (e) => {
        setAssignment({
            name: e.target.value,
            subject: assignment.subject,
        })
    }
    const handleAddsubject = (e) => {
        setAssignment({
            name: assignment.name,
            subject: e.target.value,
        })
    }
    const submitNewAssignment = (e) => {
        e.preventDefault();
        addAssignment(assignment);
        setAssignment({
            name: '',
            subject: '',
        });
    }
    return (
        <form onSubmit={submitNewAssignment}>
            <label>Please enter a new assignment...</label>
            <input type='text' placeholder='Assignment name' value={assignment.name} onChange={handleAddName}></input>
            <input type='text' placeholder='Subject' value={assignment.subject} onChange={handleAddsubject}></input>
            <Button text='Submit' />
        </form>
    )
}

export default AssignmentInput
import React from 'react'
import { v4 as uuidv4 } from 'uuid';
import Assignment from './Assignment';

const AssignmentDisplay = ({ assignments }) => {

    return (
        <div>
            {assignments.map((assignment) => {
                return (
                    <div key={uuidv4()}>
                        <Assignment name={assignment.name} subject={assignment.subject}/>
                    </div>
                )
            })}
        </div>
    )
}

export default AssignmentDisplay
import React from 'react'
import { FaTimes, FaCheckCircle } from 'react-icons/fa'

const Assignment = ({ name, subject }) => {
    return (
        <div>
            <FaCheckCircle style={{color: 'green', cursor: 'pointer'}} />
            <h6 className='assignment-names'>
                {name}
                <FaTimes 
                    style={{color: 'red', cursor: 'pointer'}} 
                />
            </h6>
            <p className='assignment-date'>
                {subject}
            </p>
        </div>
    )
}

export default Assignment

问题

当您为每个元素生成一个新的 GUID 时,您实际上是在为映射到 DateDisplay 中的每个 Date 组件使用随机 React 密钥。

const DatesDisplay = ({ dates }) => {
  return (
    <div className='assignment-display'>
      {dates.map((date) => {
        return (
          <div key={uuidv4()}> // <-- new unique key each render
            <Date date={date}/>
          </div>
        )
      })}
    </div>
  )
}

如果每个元素的 React 键在渲染之间不稳定,那么 React 会将其解释为一个新组件并卸载先前的“实例”并安装一个新的“实例”,从而丢弃任何组件状态。

解决方案

一个理想的解决方案可能是将赋值数组存储在 AssignmentCalendar 组件的 dates 状态数组中,但要专门解决这个问题,您只需要为每个 date 元素处于 dates 状态。为此,我建议在将新日期添加到状态时将 GUID 生成移动到 AssignmentCalendar 组件中。

const AssignmentCalendar = () => {
  const [dates, setDates] = useState([]);

  const addDate = (date) => {
    setDates(dates.concat({
      id: uuidv4(), // <-- generate GUID id property
      date,
    }));
  };

  return (
    <main className="main-display">
      <h3>Assignment Calendar</h3>
      <h4 className="dates-Title">Dates</h4>
      <button type="button">Add Date</button>
      <DatesInput dates={dates} addDate={addDate} />
      <DatesDisplay dates={dates} />
    </main>
  );
};

在映射时解构DatesDisplay中的dateid,仍然使用id作为React key。

const DatesDisplay = ({ dates }) => {
  return (
    <div className="assignment-display">
      {dates.map(({ date, id }) => (
        <div key={id}> // <-- now a stable id
          <Date date={date} />
        </div>
      ))}
    </div>
  );
};