如何切换位于来自 API 的另一个数组的每个对象内的数组的显示?

How can I toggle the display of an array that is located within each object of another array that comes from an API?

例如: 我正在向网站显示来自 API 的多个 Student 对象。每个 Student 对象都包含他们的测试数组 Grades 以及其他学生信息。现在,我想在屏幕上显示每个 Student 的信息,而不是显示学生的 Grades,我希望每个 Student 都有一个 "+" Button 这将切换学生 Grades.

的显示

我正在使用 React 的 useState 挂钩。我的问题是,当我单击 "+" Button 时,它会切换所有学生的成绩 on/off。我想要的是仅切换我单击其按钮的学生的 Grades

这是我的代码:

import axios from 'axios';
import { useState, useEffect } from 'react';
import styles from "./Home.module.css";
import { v4 as uuidv4 } from 'uuid';

const Home = () => {

  const [students, setStudents] = useState([]);
  const [filteredStudents, setFilteredStudents] = useState([]);
  const [isShown, setIsShown] = useState(true);

  const fetchStudents = async () => {
    const response = await axios.get(`https://api.hatchways.io/assessment/students`);
    setStudents(response.data.students);
    setFilteredStudents(response.data.students);
    console.log(response.data.students);

  }

  const findAverageGrade = arr => {
    let sum = 0;
    for (let i = 0; i < arr.length; i++) {
      sum += parseInt(arr[i]);
    }
    return sum / arr.length;
  }

  const searchStudentName = async (searchName) => { 
    const searchNameFiltered = searchName.toLowerCase();
    console.log(searchNameFiltered);
    
    if (searchNameFiltered === "") {
      fetchStudents();
      return;
    }

    var newArray = await students.filter((student) => {
      return student.firstName.toLowerCase().includes(searchNameFiltered)
      || student.lastName.toLowerCase().includes(searchNameFiltered);
    })

    await setFilteredStudents(newArray);
  }

  const toggleGrades = () => {
    console.log("toggle");
    
  }


  useEffect(() => {
    fetchStudents();

  }, [])
  

  return(
    <>
      <div>
        <input type="text" placeholder="Search by name" onChange={(event) => searchStudentName(event.target.value) }/>
        {filteredStudents.map((student) => (
          <div key={student.email} className={styles.studentItem}>
            <img className={styles.studentImage} src={student.pic} />
            <div className={styles.studentInfoContainer}>
              <div className={styles.studentHeader}>
                <p className={styles.studentName}>{student.firstName} {student.lastName}</p>
              </div>
              <ul className={styles.studentDetail}>
                <li>Email: {student.email}</li>
                <li>Company: {student.company}</li>
                <li>Skill: {student.skill}</li>
                <li>Average: {findAverageGrade(student.grades)}%</li>

                <button onClick={() => {
                  setIsShown(!isShown);
                }}>
                  +
                </button>
                {isShown ? <div>
                  <table className={styles.gradesTable}>
                    <tbody>
                      {student.grades.map((grade) => (
                        <tr key={uuidv4()}>
                          <td>Test</td>
                          <td>{grade}%</td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
                : null }
              </ul>
            </div>
          </div>
        )
      )}
      </div>
    </>
  )
  
}

export default Home;

只需将映射部分移除到另一个组件并在映射部分中导入即可。通过这种方式,您将拥有相同的结构,并且无需任何额外逻辑即可工作

新组件

const Students = ({student}) => {

            const [isShown, setIsShown] = useState(true);
            return (
              <div key={student.email} className={styles.studentItem}>
                    <img className={styles.studentImage} src={student.pic} />
                    <div className={styles.studentInfoContainer}>
                      <div className={styles.studentHeader}>
                        <p className={styles.studentName}>{student.firstName} {student.lastName}</p>
                      </div>
                      <ul className={styles.studentDetail}>
                        <li>Email: {student.email}</li>
                        <li>Company: {student.company}</li>
                        <li>Skill: {student.skill}</li>
                        <li>Average: {findAverageGrade(student.grades)}%</li>

                        <button onClick={() => {
                          setIsShown(!isShown);
                        }}>
                          +
                        </button>
                        {isShown ? <div>
                          <table className={styles.gradesTable}>
                            <tbody>
                              {student.grades.map((grade) => (
                                <tr key={uuidv4()}>
                                  <td>Test</td>
                                  <td>{grade}%</td>
                                </tr>
                              ))}
                            </tbody>
                          </table>
                        </div>
                        : null }
                      </ul>
                    </div>
               </div>
          )
}

主页组件

import axios from 'axios';
import { useState, useEffect } from 'react';
import styles from "./Home.module.css";
import { v4 as uuidv4 } from 'uuid';

const Home = () => {

  const [students, setStudents] = useState([]);
  const [filteredStudents, setFilteredStudents] = useState([]);

  const fetchStudents = async () => {
    const response = await axios.get(`https://api.hatchways.io/assessment/students`);
    setStudents(response.data.students);
    setFilteredStudents(response.data.students);
    console.log(response.data.students);

  }

  const findAverageGrade = arr => {
    let sum = 0;
    for (let i = 0; i < arr.length; i++) {
      sum += parseInt(arr[i]);
    }
    return sum / arr.length;
  }

  const searchStudentName = async (searchName) => { 
    const searchNameFiltered = searchName.toLowerCase();
    console.log(searchNameFiltered);
    
    if (searchNameFiltered === "") {
      fetchStudents();
      return;
    }

    var newArray = await students.filter((student) => {
      return student.firstName.toLowerCase().includes(searchNameFiltered)
      || student.lastName.toLowerCase().includes(searchNameFiltered);
    })

    await setFilteredStudents(newArray);
  }

  const toggleGrades = () => {
    console.log("toggle");
    
  }


  useEffect(() => {
    fetchStudents();

  }, [])
  

  return(
    <>
      <div>
        <input type="text" placeholder="Search by name" onChange={(event) => searchStudentName(event.target.value) }/>
        {filteredStudents.map((student) => (
           <Student student={student} />
        )
      )}
      </div>
    </>
  )
  
}

export default Home;

注意:我没有包括组件的导出导入部分 css 但这是简单的部分