问题
I am filtering an array of students based on input from the textbox. How can I get this to work to show students as you type out the first name? My solution is working, but obviously, if you were to backspace, the student array does not re populate. How can I get this to filter as you type the name of the student and also repopulate the array when you backspace?
function App() {
const [student, setStudent] = useState([]);
useEffect(() => {
fetch(api)
.then((response) => response.json())
.then((result) => {
setStudent(result.students);
})
.catch((err) => {
console.error(err);
});
}, [setStudent]);
const filter = (e) => {
for (let i = 0; i < student.length; i++) {
const searchedStudent = student.filter((name) => {
return name.firstName.toLowerCase().includes(e.target.value);
});
setStudent(searchedStudent);
}
};
return (
<>
<input
placeholder="Search by name"
type="text"
className="filter-students"
onChange={filter}
/>
{student.map((students) => {
let total = 0;
for (let i = 0; i < students.grades.length; i++) {
total += parseInt(students.grades[i]);
}
const average = total / students.grades.length;
console.log(average);
return (
<ul className="student-container">
<img className="student-img" src={students.pic} />
<div className="student-column">
<li className="student-item">
{" "}
{students.firstName} {students.lastName}
</li>
<li className="student-item">Email: {students.email}</li>
<li className="student-item">Company: {students.company}</li>
<li className="student-item">Skill: {students.skill}</li>
<li className="student-item">Average: {average}%</li>
</div>
</ul>
);
})}
</>
);
}
回答1:
The problem is student
state gets updated every time the <input>
changes.
Note that filtering results into a derived data coming from the original data.
Thus, NO NEED to store the filtered/derived results as a state.
Rather, you need to have another state for the text used for filtering.
const [student, setStudent] = useState([]);
const [filter, setFilter] = useState(""); // state for the text filter
<input
placeholder="Search by name"
type="text"
className="filter-students"
onChange={(e) => setFilter(e.target.value)}
/>
{students
.filter((name) => name.firstName.toLowerCase().includes(filter)) // use filter state
.map(/* Add elements here */)
}
回答2:
Don't filter your state and save it back over itself, this doesn't allow you to get back to your original state. Instead, use a separate piece of state to save the filter value and filter in-line when rendering state so you can keep your student
data intact and unmutated by filtering.
function App() {
const [student, setStudent] = useState([]);
const [filterValue, setfilterValue] = useState(""); // <-- filter state
return (
<>
<input
placeholder="Search by name"
type="text"
className="filter-students"
onChange={(e) => setFilterValue(e.target.value)} // <-- update filter state
/>
{student
.filter((name) => { // <-- filter inline
return name.firstName.toLowerCase().includes(e.target.value);
})
.map((students) => {
let total = 0;
for (let i = 0; i < students.grades.length; i++) {
total += parseInt(students.grades[i]);
}
const average = total / students.grades.length;
console.log(average);
return (
<ul className="student-container">
<img className="student-img" src={students.pic} />
<div className="student-column">
<li className="student-item">
{" "}
{students.firstName} {students.lastName}
</li>
<li className="student-item">Email: {students.email}</li>
<li className="student-item">Company: {students.company}</li>
<li className="student-item">Skill: {students.skill}</li>
<li className="student-item">Average: {average}%</li>
</div>
</ul>
);
})}
</>
);
}
来源:https://stackoverflow.com/questions/64674657/filtering-array-based-on-each-letter-from-input