React组件内如何实现基于状态的姓名、标签双条件学生数据过滤
核心问题
标签状态仅存储在Profile组件的内部状态中,父组件App无法访问该数据,无法实现跨组件的标签过滤逻辑,需通过状态提升将标签数据放到顶层App组件统一管理。
分步修改方案
1. 改造App.js
初始化学生数据时新增tags字段,新增标签搜索状态、标签更新方法、双条件过滤逻辑:
import { useState, useEffect } from 'react' import axios from 'axios' import SearchBar from './SearchBar' import Profile from './Profile' function App() { const [students, setStudents] = useState([]) const [filteredStudents, setFilteredStudents] = useState([]) const [nameSearch, setNameSearch] = useState("") // 新增标签搜索状态 const [tagSearch, setTagSearch] = useState("") // 请求数据时给每个学生初始化空tags数组 useEffect(()=>{ axios.get('Link to the API') .then(res => { const result = res.data.students.map(student => ({ ...student, tags: [] })) setStudents(result) }) },[]) // 新增:更新指定学生的标签数组 const updateStudentTags = (studentId, newTags) => { setStudents(prev => prev.map(student => student.id === studentId ? {...student, tags: newTags} : student )) } // 双条件过滤逻辑:同时匹配姓名、标签 useEffect(() => { const lowerNameQuery = nameSearch.toLowerCase() const lowerTagQuery = tagSearch.toLowerCase() const searchResult = students.filter(student => { // 姓名匹配 const fullName = `${student.firstName} ${student.lastName}`.toLowerCase() const nameMatch = !nameSearch || fullName.includes(lowerNameQuery) // 标签匹配 const tagMatch = !tagSearch || student.tags.some(tag => tag.toLowerCase().includes(lowerTagQuery) ) // 两个条件同时满足才返回 return nameMatch && tagMatch }) setFilteredStudents(searchResult) }, [nameSearch, tagSearch, students]) return ( <div> <SearchBar search={nameSearch} onChange={e => setNameSearch(e.target.value)} placeholder="按姓名搜索" /> {/* 新增标签搜索框 */} <SearchBar search={tagSearch} onChange={e => setTagSearch(e.target.value)} placeholder="按标签搜索" /> {/* 无需再区分搜索框是否为空,统一渲染过滤后的列表即可 */} <div> {filteredStudents.map(student => ( <Profile key={student.id} student={student} updateTags={(newTags) => updateStudentTags(student.id, newTags)} /> ))} </div> </div> ) } export default App
2. 改造Profile.js
移除内部tags状态,改用父组件传入的tags和更新方法:
import { useState } from 'react' import Tag from './Tag' function Profile({ student, updateTags }) { // 仅保留标签输入框的临时输入状态,永久标签从props取 const [tagInput, setTagInput] = useState("") function handleKeyPress(e) { if(e.key === 'Enter' && tagInput.trim()) { // 调用父组件方法更新标签,不直接修改原数组 updateTags([...student.tags, tagInput.trim()]) setTagInput("") } } return( <div> {/* 原有学生信息渲染逻辑保持不变 */} <Tag onChange={e => setTagInput(e.target.value)} onKeyPress={handleKeyPress} tags={student.tags} tag={tagInput} /> </div> ) } export default Profile
3. 改造Tag.js(可选优化)
仅新增遍历标签的key属性,避免React告警,原有逻辑无变动:
export default function Tag({tag, tags, onChange, onKeyPress}) { return ( <div> {tags.length > 0 && <div> {tags.map((tag, index) => ( <span key={index}>{tag}</span> ))} </div> } <input type='text' value={tag} placeholder="Add a tag" key='tag-input' onKeyPress={onKeyPress} onChange={onChange} /> </div> ) }
内容的提问来源于stack exchange,提问作者SelfTaughtLooking4Job
相关产品推荐
相关产品推荐

