React父子组件参数传递:将TagsInput搜索功能移至父组件
我懂你的需求了——要把搜索功能从子组件抽出来放到父组件,让多个循环渲染的TagsInput共用一个搜索框,同时每个子组件管好自己的标签组。这用React的状态提升就能搞定,下面是具体的实现步骤:
首先,我们先改造子组件TagsInput,把它内部的搜索和标签状态全部移除,改成通过props接收数据和回调:
import React from 'react' function TagsInput(props) { // 不再维护自己的tags和search状态,全靠父组件传过来 const addTags = event => { if (event.key === "Enter" && event.target.value.trim() !== "") { // 调用父组件的添加回调,告诉它是哪个标签组要加新标签 props.onAddTag(props.groupId, event.target.value.trim()); event.target.value = ""; } }; const removeTags = tagIndex => { // 同样,通知父组件要删除哪个标签组里的哪个标签 props.onRemoveTag(props.groupId, tagIndex); }; return ( <div className="tags-input"> <ul> {/* 直接渲染父组件传过来的过滤后的标签 */} {props.filteredTags.map((tag, index) => ( <li key={index}> <span>{tag}</span> <i className="material-icons" onClick={() => removeTags(index)}>x</i> </li> ))} </ul> <input type="text" onKeyUp={addTags} placeholder="Press enter to add tags" /> </div> ) } export default TagsInput
接下来是父组件的实现,它要承担起全局搜索状态管理、多个标签组的维护,以及过滤逻辑的工作:
import React, { useState, useMemo } from 'react' import TagsInput from './TagsInput' function ParentComponent() { // 全局的搜索关键词,所有子组件共用这个状态 const [searchKeyword, setSearchKeyword] = useState(""); // 存储多个标签组,这里假设你要渲染3个TagsInput,初始化三个空数组 // 如果是动态生成的,你可以根据自己的数据源来初始化 const [tagsGroups, setTagsGroups] = useState([[], [], []]); // 处理添加标签:找到对应的标签组,添加新标签 const handleAddTag = (groupId, newTag) => { const updatedGroups = [...tagsGroups]; updatedGroups[groupId] = [...updatedGroups[groupId], newTag]; setTagsGroups(updatedGroups); // 如果需要把所有标签汇总传给上层组件,这里可以加逻辑 // 比如 props.onAllTagsSelected(updatedGroups.flat()) }; // 处理删除标签:定位到目标标签组,删除指定索引的标签 const handleRemoveTag = (groupId, tagIndex) => { const updatedGroups = [...tagsGroups]; updatedGroups[groupId] = updatedGroups[groupId].filter((_, idx) => idx !== tagIndex); setTagsGroups(updatedGroups); }; // 用useMemo缓存过滤结果,避免每次渲染都重复计算,提升性能 const filteredTagsGroups = useMemo(() => { const lowerCaseKeyword = searchKeyword.toLowerCase(); return tagsGroups.map(group => group.filter(tag => tag.toLowerCase().includes(lowerCaseKeyword)) ); }, [tagsGroups, searchKeyword]); return ( <div> {/* 父组件的搜索框,唯一的搜索入口 */} <div className="search-bar"> <input value={searchKeyword} onChange={(e) => setSearchKeyword(e.target.value)} placeholder="Search all tags..." /> </div> {/* 循环渲染多个TagsInput,每个都拿到自己的标签组和回调 */} <div className="tags-inputs-wrapper"> {filteredTagsGroups.map((_, groupId) => ( <TagsInput key={groupId} groupId={groupId} // 给每个子组件一个唯一标识,方便父组件定位 filteredTags={filteredTagsGroups[groupId]} // 过滤后的标签列表 onAddTag={handleAddTag} onRemoveTag={handleRemoveTag} /> ))} </div> </div> ) } export default ParentComponent
关键要点解释:
- 状态提升:把原本子组件里的
search和tags状态移到父组件,这样父组件能统一控制搜索行为,同时管理所有子组件的标签数据。 - 唯一标识:给每个子组件传
groupId(这里用循环的索引,实际项目中如果是动态生成的,建议用更稳定的唯一值,比如后端返回的ID),让父组件知道操作的是哪一个标签组。 - 性能优化:用
useMemo缓存过滤后的标签组,只有当搜索关键词或标签组变化时才重新计算,避免不必要的重渲染。 - 回调通信:父组件定义添加/删除标签的回调函数,子组件触发这些回调来通知父组件更新状态,这是React中子父组件通信的标准方式。
这样改造后,子组件就没有了自己的搜索框,所有搜索都由父组件的唯一搜索框控制,多个TagsInput会同步根据搜索关键词过滤各自的标签,完全符合你的需求。
内容的提问来源于stack exchange,提问作者Payne
相关产品推荐
相关产品推荐

