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

React中checkOut后useEffect重置numStudents状态的解决求助

问题分析与解决

你的问题核心是状态不同步:

  • checkOut操作只是给学生添加了checkOutTime,并没有从students数组里删除学生,所以students.length根本没变
  • 你手动调用setNumStudents(students.length-1)是错误的,而且紧接着useEffect会因为students状态更新被触发,把numStudents重置为当前students.length,直接覆盖了你手动设置的值

最优解决方案:删除冗余状态,直接计算在校人数

不需要单独维护numStudents状态,在校学生数是从students数组派生出来的——只需要统计数组中没有checkOutTime的学生数量即可,这样完全避免状态不同步问题。

修改步骤:

  1. 删除numStudents状态声明:去掉const [numStudents, setNumStudents] = useState(0);
  2. 添加计算属性:在组件里直接计算当前在校人数
    const numStudents = students.filter(student => !student.checkOutTime).length;
    
  3. 删除监听students的useEffect:不需要再通过副作用同步状态
  4. 删除checkOut里的setNumStudents调用:现在不需要手动更新这个值了

修改后的完整代码

const Attendance = () => {
    // Declare state variables
  const [students, setStudents] = useState([]);

  // 计算当前在校学生数:过滤出未签退的学生
  const numStudents = students.filter(student => !student.checkOutTime).length;

  // Function to add a student to the attendance list
  const addStudent = (rollNumber, name) => {
    setStudents(
      students.concat({
        rollNumber,
        name,
        checkInTime: new Date().toLocaleString(),
      })
    );
};

// Function to check a student out
const checkOut = (rollNumber) => {
    setStudents(
        students.map((student) => {
            if (student.rollNumber === rollNumber) {
                return { ...student, checkOutTime: new Date().toLocaleString() };
            }
            return student;
        })
        );
  };

  return (
    <div>
        {/* Form to input student roll number and name */}
      <form
        onSubmit={(e) => {
          e.preventDefault();
          addStudent(e.target.rollNumber.value, e.target.name.value);
          e.target.rollNumber.value = "";
          e.target.name.value = "";
        }}
      >
        <div className="container">
          <h1>Student Attendance</h1>
          <label>
            Roll Number
            <input type="number" name="rollNumber" />
          </label>
          <br />
          <label>
            Name
            <input type="text" name="name" />
          </label>
          <br />
          <button type="submit">Check In</button>
        </div>
      </form>
      {/* Display number of students present */}
      <p>There are currently {numStudents} students in the school.</p>
       {/* Table to display list of students and their check in/out times */}
      <br />
      <table className="fl-table">
        <thead>
          <tr>
            <th>Roll Number</th>
            <th>Name</th>
            <th>Check In Time</th>
            <th>Check Out Time</th>
          </tr>
        </thead>
        <tbody>
          {students.map((student) => (
            <tr key={student.rollNumber}>
              <td>{student.rollNumber}</td>
              <td>{student.name}</td>
              <td>{student.checkInTime.toString()}</td>
              <td>
                {student.checkOutTime ? (student.checkOutTime.toString()) : (
                  <button
                    onClick={() => checkOut(student.rollNumber)}>
                    Check Out
                  </button>
                )}
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};

export default Attendance;

额外优化点

  • 去掉了button上重复的key属性(因为父元素tr已经有key了)
  • 派生状态直接计算,符合React状态管理的最佳实践:尽量只维护最小必要状态,派生状态通过计算得到

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 20:02:20