React JS中如何将输入值作为标签添加到对象数组并展示
问题修复&实现方案
首先修正原代码里的显性bug:
- render方法里loading判断拼写错误,
this.state.loadin少写了末尾的g,会导致loading状态永远不生效 - 全局
input状态是给搜索框用的,不要和单条人员的标签输入混用,标签输入不需要放到全局state,输入完成触发添加时再取值即可
核心实现逻辑
- 标签直接存储在对应
people数组的人员对象上,新增标签时遵循React不可变数据原则,不直接修改原state对象,通过拷贝生成新对象更新
注意:直接修改原state里的对象属性,React无法检测到数据变化,不会触发页面重渲染 - 首次给某个人加标签时,给该对象新增
tags字段,值为存第一个标签的数组;后续加标签直接把新值追加到该人员的tags数组即可 - 标签输入用回车触发添加,避免输入过程中频繁触发state更新,添加完成后自动清空输入框
- 渲染人员项时遍历对应人员的
tags数组,展示所有已添加的标签
关键代码说明
1. 新增标签添加方法
在组件内新增处理标签添加的类方法,通过人员id定位要更新的数组项:
addTag = (personId, inputValue) => { // 过滤空标签 const tagVal = inputValue.trim() if (!tagVal) return this.setState(prevState => ({ people: prevState.people.map(person => { // 非当前操作的人员项直接返回,不做修改 if (person.id !== personId) return person // 当前操作的人员,返回更新后的新对象 return { ...person, // 已有tags就追加新值,没有就初始化数组存第一个标签 tags: person.tags ? [...person.tags, tagVal] : [tagVal] } }) })) }
2. 修改列表渲染逻辑
给每个人员项的标签输入框绑定回车事件,同时增加标签展示区域,去掉不必要的JSON.stringify包裹:
const list = this.state.people.filter(person => this.state.searchInput.toLowerCase() === '' || person.firstName.toLowerCase().includes(this.state.searchInput.toLowerCase()) || person.lastName.toLowerCase().includes(this.state.searchInput.toLowerCase()) ) .map(person => ( <div key={person.id}> <li> {person.firstName} {person.lastName} {/* 标签展示区域 */} <div className="tag-wrap"> {person.tags?.map((tag, index) => ( <span className="tag-item" key={index}>{tag}</span> ))} </div> {/* 标签输入框 */} <input type="text" placeholder="输入标签按回车添加" onKeyDown={e => { if (e.key === 'Enter') { this.addTag(person.id, e.target.value) // 添加完成清空输入框 e.target.value = '' } }} /> </li> </div> ));
3. 修复loading判断拼写
把render里的错误判断修正:
if (this.state.loading) { return <div>loading...</div>; }
完整修正后代码
import React from "react"; import "./App.css"; export default class FetchRandomUser extends React.Component { state = { loading: true, people: [], searchInput: '', // 语义化命名,和其他输入做区分 } async componentDidMount() { const url = "https://api.hatchways.io/assessment/students"; const response = await fetch(url); const data = await response.json(); this.setState({ people: data.students, loading: false }); } // 搜索输入处理,用箭头函数避免手动绑定this onSearchChange = (e) => { this.setState({ searchInput: e.target.value, }) } // 添加标签处理 addTag = (personId, inputValue) => { const tagVal = inputValue.trim() if (!tagVal) return this.setState(prevState => ({ people: prevState.people.map(person => { if (person.id !== personId) return person return { ...person, tags: person.tags ? [...person.tags, tagVal] : [tagVal] } }) })) } render() { if (this.state.loading) { return <div>loading...</div>; } if (!this.state.people.length) { return <div>didnt get person...</div>; } const list = this.state.people.filter(person => this.state.searchInput.toLowerCase() === '' || person.firstName.toLowerCase().includes(this.state.searchInput.toLowerCase()) || person.lastName.toLowerCase().includes(this.state.searchInput.toLowerCase()) ) .map(person => ( <div key={person.id}> <li> <div>{person.firstName} {person.lastName}</div> <div className="tag-wrap"> {person.tags?.map((tag, index) => ( <span key={index} style={{margin: '0 4px', padding: '2px 6px', background: '#eee', borderRadius: '4px'}} > {tag} </span> ))} </div> <input type="text" placeholder="输入标签按回车添加" onKeyDown={e => { if (e.key === 'Enter') { this.addTag(person.id, e.target.value) e.target.value = '' } }} /> </li> </div> )); return ( <div> <div className="example1"> <input value={this.state.searchInput} type="text" placeholder="搜索学生姓名" onChange={this.onSearchChange} /> <ul>{list}</ul> </div> </div> ) } }
可以自行给标签加对应CSS样式调整显示效果,现在输入标签按回车就会给对应学生添加标签,多次输入就会按顺序追加到对应人员的tags数组里。
内容的提问来源于stack exchange,提问作者meetStackOverflow
相关产品推荐
相关产品推荐

