首页 > 解决方案 > 在 React 中单击按钮时,如何仅展开一个列表项(无挂钩)?

问题描述

我有一个学生列表,我想制作一个可扩展的列表视图。基本上每个学生都会有一个加号和减号按钮,每次点击它时,所有学生成绩的列表都会扩大。但是,到目前为止,当我单击其中一个按钮时,它会同时打开所有学生的成绩列表。

我似乎无法弄清楚如何解决此问题,以便当我单击特定学生时,它只会打开该学生的成绩。谁可以帮我这个事?我想我已经接近了,但我无法到达那里!

这是我的代码:

import React from 'react';
import Average from './Average';
import './App.css';

class App extends React.Component{

  state = {
    students: [],
    error: null,
    search: null,
    open: false,
  }

  componentDidMount(){
    fetch('https://api.hatchways.io/assessment/students')
      .then(res => res.json())
      .then(
        (data) => {
        this.setState({ 
          students: data.students,
        })
      },
      (error) => {
        this.setState({ error });
      })
  }
  
  handleChange = (e) => {
    this.setState({ search: e.target.value });
  }

  togglePanel = e => {
    this.setState({ open: !this.state.open })
  }


  render(){
    let { search, students, open } = this.state;
    const display = students.filter((student) => {
      if(search == null)
        return student;
      else if(student.firstName.toLowerCase().includes(search.toLowerCase()) || 
              student.lastName.toLowerCase().includes(search.toLowerCase())){
        return student;
      }
    }).map((student, idx) => {
      return (
        <div className = "student-container" key = {student.id}>
          <img className = "student-pic" src = {student.pic} alt = "pictures"/>
          <div className = "student-mini">
            <h1>{student.firstName.toUpperCase()} {student.lastName.toUpperCase()}</h1>
            <p>Email: {student.email}</p>
            <p>Company: {student.company}</p>
            <p>Skill: {student.skill}</p>
            <Average grades = {student.grades}/>
            <button onClick = {(e) => this.togglePanel(e)}>{open ? '-' : '+'}</button>
            <div>
            <p>{open ? student.grades.map((grade, id) => {
                return (
                  <p key = {id}>Test {id + 1}: {grade}%</p>
                )
              }): null}
            </p>
            </div>
          </div>
        </div>
      )
    })

    return (
      <div className = "gray-container">
        <div className = "white-container">
          <form>
            <input onChange = {this.handleChange} type = "text" placeholder = "Search by 
             name">
            </input>
          </form>
          <div>
            {display}
          </div>
        </div>
      </div>
    )
  }
}

export default App;

标签: javascriptreactjs

解决方案


您的每个可扩展面板都使用相同的单一open状态来确定是否应该扩展它,这就是它们同时打开的原因。这里最简单的解决方案是让每个面板都有自己的状态。

理想情况下,您希望从地图的 return 语句中提取 JSX 以分离呈现单个学生面板的组件,例如StudentPanel,将学生对象作为道具传递,并将open状态和切换功能也移动到该组件。

更新:你会有这样的事情:

class StudentPanel extends React.Component {
  state = {
    open: false
  }

  togglePanel = e => {
    this.setState(prevState => ({ open: !prevState.open }))
  }

  render() {
    const { student } = this.props;

    return (
      <div className = "student-container" key = {student.id}>
        // (...) rest of JSX
      </div>
    );  
  }
}

render你的App你有:

(...).map(student => <StudentPanel student={student} />)

open属性,togglePanel可以完全从App组件中删除。


推荐阅读