I'm reading from an API and displaying each student's information onto the web browser. My goal is to make each student have a text input field in which you are able to add a 'tag' for the specific student.
My problem: Currently, I have given each student a text input field but when I enter a 'tag' for ANY of the students, it only adds the tag to the FIRST student.
Home.jsx
import axios from 'axios';
import { useState, useEffect } from 'react';
import Students from '../components/Students';
import styles from "./Home.module.css";
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 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);
}
useEffect(() => {
fetchStudents();
}, [])
return(
<>
<div>
<input className={styles.nameSearchInput} type="text" placeholder="Search by name" onChange={(event) => searchStudentName(event.target.value) }/>
{filteredStudents.map((student) => (
<Students key={student.id} student={student} />
))}
</div>
</>
)
}
export default Home;
Students.jsx
import { useState } from 'react';
import styles from "../views/Home.module.css";
import { v4 as uuidv4 } from 'uuid';
import AddIcon from '@mui/icons-material/Add';
import RemoveIcon from '@mui/icons-material/Remove';
const Students = ({student}) => {
const [isShown, setIsShown] = useState(true);
const findAverageGrade = arr => {
let sum = 0;
for (let i = 0; i < arr.length; i ) {
sum = parseInt(arr[i]);
}
return sum / arr.length;
}
const addTag = (event) => {
if (event.key === 'Enter') {
document.getElementById("tag-output").innerHTML = `
<p id="tag">${event.target.value}</p>
`;
document.getElementById("tag-input").value = "";
}
}
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.toUpperCase()} {student.lastName.toUpperCase()}</p>
<button className={styles.expandBtn} onClick={() => {
setIsShown(!isShown);
}}>
{ isShown ? <AddIcon className={styles.expandBtn} /> : <RemoveIcon className={styles.expandBtn} /> }
</button>
</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>
{!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 }
<div id="tag-output"></div>
<input id="tag-input" className={styles.addTagInput} type="text" placeholder="Add a tag" onKeyPress={(e) => addTag(e)}/>
</ul>
</div>
</div>
)
}
export default Students;
CodePudding user response:
use array state and append it with new values like this
play live code here live_demo
import React, { useState } from "react";
export default function Main(props) {
const [tags, setTags] = useState([]);
return (
<div className="App">
<input
type="text"
onKeyDown={(e) => {
if (e.key === "Enter" && !e.shiftKey && e.target.value !== "") {
let val = e.target.value;
e.target.value = "";
setTags([...tags, val]);
}
}}
/>
<div className="tags">
<ol className="each-tag">
{tags.map((tag, i) => {
return <li key={i}>{tag}</li>;
})}
</ol>
</div>
</div>
);
}