我如何管理反应 js 中每一行的状态?

How do I manage the state of each row in react js?

我正在将数据库中的数据映射到 html table,其中每一行都有一个切换按钮来标记它们是否存在。但是我不确定如何保存每行切换按钮的状态,因为它们都会有所不同。

function Component() {
  const [students, setStudents] = useState([]);
  const [absent, setAbsent] = useState(false);
  const updateAbsent = () => {
    console.log(absent);
  };

  return (
    <div className="attendance-today-container">
      <h1>Daily attendance</h1>
      <table ref={table}>
        <tr>
          <th>First Name</th>
          <th>Last Name</th>
          <th>Absent?</th>
        </tr>
        {students.map((student, i) => {
          return (
            <tr>
              <td key={i}>{student.firstName}</td>
              <td>{student.lastName}</td>
              <td>
                <label class="switch">
                  <input
                    type="checkbox"
                    onClick={() => {
                      setAbsent(!absent);
                    }}
                  />
                  <span class="slider round"></span>
                </label>
              </td>
            </tr>
          );
        })}
      </table>
      <button onClick={updateAbsent}>Send</button>
    </div>
  );
}

一种简单的方法是存储学生数据,以及他们是否存在于同一状态。

每个学生都可以有一个id,方便识别。一个函数可以遍历学生状态数组并使用 id 标识哪个学生被标记为缺席或在场。

const data = [
    { id: 1, firstName: 'John', lastName: 'Doe', absent: false },
    { id: 2, firstName: 'Jane', lastName: 'Doe', absent: false },
];

const StudentList = () => {
    const [students, setStudents] = useState(data);
    const updateAbsent = () => {
        const absents = students.filter((student) => student.absent === true);
        console.log(absents);
    };
    const handleToggleAbsent = (toggleStudent) => {
        setStudents((prevStudents) =>
            prevStudents.map((student) => {
                if (student.id !== toggleStudent.id) return student;
                return { ...student, absent: !student.absent };
            })
        );
    };

    return (
        <div className="attendance-today-container">
            <h1>Daily attendance</h1>
            <table>
                <thead>
                    <tr>
                        <th>First Name</th>
                        <th>Last Name</th>
                        <th>Absent?</th>
                    </tr>
                </thead>
                <tbody>
                    {students.map((student) => {
                        return (
                            <StudentItem
                                student={student}
                                key={student.id}
                                onToggleAbsent={handleToggleAbsent}
                            />
                        );
                    })}
                </tbody>
            </table>
            <button onClick={updateAbsent}>Send</button>
        </div>
    );
};

const StudentItem = (props) => {
    const { student, onToggleAbsent } = props;
    return (
        <tr>
            <td>{student.firstName}</td>
            <td>{student.lastName}</td>
            <td>
                <label className="switch">
                    <input
                        type="checkbox"
                        onClick={onToggleAbsent.bind(null, student)}
                    />
                    <span className="slider round"></span>
                </label>
            </td>
        </tr>
    );
};

export default StudentList;

这个概念与 Sheik Yerbouti 所建议的和 SamiElk 所展示的一致。

获取学生对象数组,并为每个对象添加一个名为absent 的属性,并将其默认设置为false。然后让相应的复选框根据数组中对象的索引及其 absent 属性 的当前值为每个学生正确切换 absent。我创建了一个名为 getData 的函数,它将模拟您的 API 调用以获取学生数据。这是代码:

import { useEffect, useState } from "react";
import "./styles.css";


const getData = () => {
  return new Promise(resolve => {
    resolve([{firstName: "John", lastName: "Marks"}, {firstName: "Garry", lastName: "Nelson"}]);
  })
}

export default function App() {
  const [students, setStudents] = useState([]);

  const markAbsent = (i) => {
    setStudents(prev => 
      prev.map((s, index) => ({...s, absent: i === index ? !s.absent : s.absent}))
    )
  }

  useEffect(() => {
    getData()
    .then(data => {
      data = data.map(i => ({absent: false, ...i}));
      setStudents(data);
    })
  }, [])

  return (
    <div className="attendance-today-container">
      <h1>Daily attendance</h1>
      <table>
        <tr>
          <th>First Name</th>
          <th>Last Name</th>
          <th>Absent?</th>
        </tr>
        {students.map((student, i) => {
          return (
            <tr>
              <td key={i}>{student.firstName}</td>
              <td>{student.lastName}</td>
              <td>
                <label class="switch">
                  <input
                    type="checkbox"
                    defaultChecked={student.absent}
                    onClick={() => markAbsent(i)}
                  />
                  <span className="slider round"></span>
                </label>
              </td>
            </tr>
          );
        })}
      </table>
      <button onClick={() => false}>Send</button>
    </div>
  );
}

请注意,我不确定 Send 按钮应该做什么,所以我离开了它 non-functional。这里有一个Sandbox link给你玩。