You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 07:30:51