如何在 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;

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

理想情况下,您希望从映射的 return 语句中提取 JSX 到呈现单个学生面板的单独组件,假设StudentPanel,将学生对象作为 prop 传递并将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>
);  
}
}

renderApp,您将拥有:

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

并且可以从组件中完全删除open属性和togglePanelApp

最新更新