I'm trying to map through an API and make each of its objects have expandable data. However, when I expand a div for one object, instead of only expanding that particular div it expands all of my objects. How do i made it so that it only expands that one object data? Here is my code:
export default function StudentsList({ students }) {
const [isCollapsed, setIsCollapsed] = useState(true);
const handleCollapse = () => {
setIsCollapsed((prev) => !prev);
};
return (
<div className={studentsBox}>
{students.map((student) => (
<div className={card} key={student.id}>
<div
className={plus}
onClick={handleCollapse}
>
{isCollapsed ? '+' : '-'}
</div>
<div className={isCollapsed ? collapse : ''}>
<p>Test 1: {student.grades[0]}%</p>
<p>Test 2: {student.grades[1]}%</p>
<p>Test 3: {student.grades[2]}%</p>
<p>Test 4: {student.grades[3]}%</p>
<p>Test 5: {student.grades[4]}%</p>
<p>Test 6: {student.grades[5]}%</p>
<p>Test 7: {student.grades[6]}%</p>
<p>Test 8: {student.grades[7]}%</p>
</div>
</div>
</div>
))}
);
}
you can do something like this
export default function StudentsList({ students }) {
const [collapsed, setCollapsed] = useState(null);
const handleCollapse = (id) => {
setCollapsed(prev => prev === id? null : id);
};
return (
<div className={studentsBox}>
{students.map((student) => (
<div className={card} key={student.id}>
<div
className={plus}
onClick={() => handleCollapse(student.id)}
onMouseMove={() => setId(`${student.id}`)}
>
{collapsed === student.id ? '+' : '-'}
</div>
<div className={collapsed === student.id ? collapse : ''}>
<p>Test 1: {student.grades[0]}%</p>
<p>Test 2: {student.grades[1]}%</p>
<p>Test 3: {student.grades[2]}%</p>
<p>Test 4: {student.grades[3]}%</p>
<p>Test 5: {student.grades[4]}%</p>
<p>Test 6: {student.grades[5]}%</p>
<p>Test 7: {student.grades[6]}%</p>
<p>Test 8: {student.grades[7]}%</p>
</div>
</div>
</div>
))}
);
}
First you declare the selectedId
const [selectedId, setSelectedId] = useState(null);
Then set onClick to setSelectedId
onClick={()=>setSelectedId(student.id)}
This way you can change the className base on the selectedId
<div className={student.id !== selectedId ? collapse : ''}>
<p>Test 1: {student.grades[0]}%</p>
<p>Test 2: {student.grades[1]}%</p>
....
</div>
The beauty of React is to make use of lots of components. Use additional components to add some structure to your presentation of your data.
StudentList (shows a list of...)
Student (which, in turn, shows a list of...)
StudentGradeEach student can easily be collapsed independently from the list of students.
function StudentGrade({ grade, index }) {
return <p>Test {index}: {grade}</p>
}
function Student({ student }) {
const [isCollapsed, setIsCollapsed] = React.useState(true);
const handleCollapse = () => {
setIsCollapsed((prev) => !prev);
};
return (
<div>
<div onClick={handleCollapse}>
{isCollapsed ? '-' : '+'}
<span>{student.name}</span>
</div>
{!isCollapsed?null:(
<div>
{student.grades.map((grade, index) => (
<StudentGrade key={index} grade={grade} index={index}/>
))}
</div>
)}
</div>
)
}
function StudentsList({ students }) {
return (
<div>
{students.map((student) => (
<Student key={student.id} student={student} />
))}
</div>
);
}
const students = [
{ id: 1, name: 'Ann', grades: ['A', 'B'] },
{ id: 2, name: 'Bob', grades: ['B', 'C'] },
{ id: 3, name: 'Charlie', grades: ['C', 'D'] },
]
ReactDOM.render(<StudentsList students={students} />, document.getElementById('root'));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>
</script>
<div id="root"></div>