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

React.js中移除列表项时的异常行为问题求助

问题分析与解决方案

你的问题核心出在两个地方:子组件状态与父组件不同步,以及列表渲染缺少唯一key标识,导致删除操作后JobRow组件无法正确更新。下面一步步帮你修复:

1. 让JobRow成为受控组件,不再维护自身state

原来的JobRow组件在constructor里把props复制到自己的state,这会导致父组件状态更新时,子组件的state不会同步。正确的做法是让父组件统一管理所有job的状态,JobRow只负责渲染和触发更新事件:

class JobRow extends React.Component {
  // 移除constructor里的state,直接使用props
  handleAddField = () => {
    // 通知父组件添加新的步骤
    const { key, onUpdateNextSteps } = this.props;
    onUpdateNextSteps(key, [...this.props.next_steps, ""]);
  };

  handleRemoveField = idx => () => {
    // 通知父组件移除指定步骤
    const { key, onUpdateNextSteps } = this.props;
    const newSteps = this.props.next_steps.filter((_, sidx) => idx !== sidx);
    onUpdateNextSteps(key, newSteps);
  };

  changeTextCompany = (event) => {
    // 通知父组件更新公司名称
    const { key, onUpdateCompany } = this.props;
    onUpdateCompany(key, event.target.value);
  };

  changeTextPosition = (event) => {
    // 通知父组件更新职位名称
    const { key, onUpdatePosition } = this.props;
    onUpdatePosition(key, event.target.value);
  };

  render() {
    const { company, position, next_steps } = this.props;
    return (
      <div>
        <div className="flex-container">
          <div className="inner_flex">
            <span>
              <input 
                type="text" 
                className="form-control" 
                placeholder="Company" 
                value={company} 
                id="comapny_input" 
                onChange={this.changeTextCompany}
              />
            </span>
            <span>
              <input 
                type="text" 
                className="form-control" 
                placeholder="Position" 
                value={position} 
                onChange={this.changeTextPosition}
                id="position_input"
              />
            </span>
            <span>
              <select id="position_type">
                <option value="fulltime">Fulltime</option>
                <option value="intern">Co-Op/Internship</option>
              </select>
            </span>
          </div>
          {next_steps.map((step, idx) => (
            <span key={idx}>
              <button type="button" onClick={this.handleRemoveField(idx)} className="small">
                -
              </button>
              <input placeholder="Next State" value={step} />
            </span>
          ))}
          <button type="button" onClick={this.handleAddField} className="small">
            Next Stage
          </button>
        </div>
      </div>
    );
  }
}

2. 父组件Jobs统一管理状态,并添加更新回调

修改Jobs组件,添加处理子组件更新的方法,同时确保每个job有唯一的key,让React能正确识别列表项:

class Jobs extends React.Component {
  constructor(props) {
    super(props);
    // 确保每个job都有唯一key(已有数据如果没有key则生成)
    this.state = {
      name: "",
      jobs: props.data.items.map(item => ({
        ...item,
        key: item.key || Date.now()
      }))
    };
  }

  handleAddJob = () => {
    this.setState({
      jobs: this.state.jobs.concat([{ 
        key: Date.now(), // 生成唯一key
        company:"", 
        position: "", 
        next_steps: []
      }])
    });
  };

  handleRemoveJob = key => () => {
    this.setState({
      jobs: this.state.jobs.filter(item => item.key !== key)
    });
  };

  // 更新公司名称的回调
  handleUpdateCompany = (key, newCompany) => {
    this.setState({
      jobs: this.state.jobs.map(job => 
        job.key === key ? {...job, company: newCompany} : job
      )
    });
  };

  // 更新职位名称的回调
  handleUpdatePosition = (key, newPosition) => {
    this.setState({
      jobs: this.state.jobs.map(job => 
        job.key === key ? {...job, position: newPosition} : job
      )
    });
  };

  // 更新步骤的回调
  handleUpdateNextSteps = (key, newSteps) => {
    this.setState({
      jobs: this.state.jobs.map(job => 
        job.key === key ? {...job, next_steps: newSteps} : job
      )
    });
  };

  render() {
    return (
      <div>
        <h4>Jobs Applied</h4>
        {this.state.jobs.map(items => (
          <div key={items.key}> {/* 给列表项设置唯一key */}
            <Welcome name={items.company} />
            <JobRow 
              key={items.key}
              company={items.company} 
              position={items.position} 
              next_steps={items.next_steps}
              onUpdateCompany={this.handleUpdateCompany}
              onUpdatePosition={this.handleUpdatePosition}
              onUpdateNextSteps={this.handleUpdateNextSteps}
            />
            <button 
              type="button" 
              onClick={this.handleRemoveJob(items.key)} 
              className="small"
            >
              remove row
            </button>
          </div> 
        ))}
        <button type="button" onClick={this.handleAddJob} className="small">
          Add New Job
        </button>
      </div>
    )
  };
}

关键修复点说明

  • 受控组件模式:让父组件管理所有状态,子组件通过props接收数据,通过回调函数通知父组件更新,这样父组件状态变化时,子组件会自动重新渲染,解决不同步问题。
  • 唯一key属性:给每个列表项设置唯一key,React会根据key识别每个元素,删除操作后不会复用错误的组件,确保UI正确更新。
  • 新增job时添加key:原来的新增job没有key,导致删除时无法匹配过滤条件,现在用Date.now()生成唯一key,确保删除操作有效。

这样修改后,删除按钮点击后,对应的JobRow会被正确移除,剩余行的内容也会正确展示。

内容的提问来源于stack exchange,提问作者Bob

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:57:22