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

React组件状态不同步:职位增删时计数器数值未更新

问题分析与解决方案

你遇到的核心问题是:Counter 和 Vacancy 是两个完全独立的组件实例,虽然 Counter 继承了 Vacancy,但它们各自维护自己的 state。当你在 Vacancy 里添加/删除职位时,只会更新它自己的内部状态,Counter 的状态完全没同步,所以计数器数值自然不会变。

要解决这个问题,我们需要把共享的状态(职位列表)提升到一个共同的父组件中,让两个子组件共用同一个数据源,这样状态变化时就能同步更新所有依赖它的组件。


具体重构方案

1. 创建父组件统一管理状态

新建一个 App.jsx 作为根组件,负责获取数据、管理职位列表状态,以及提供删除职位的方法:

import React from 'react';
import { Vacancy } from './vacancies';
import { Counter } from './counter';

export class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { vacancies: [], loading: true };
    // 绑定删除方法到组件实例
    this.handleDelete = this.handleDelete.bind(this);
  }

  // React 推荐在 componentDidMount 中发起异步请求
  componentDidMount() {
    fetch('/api/Vacancy/Vacancies')
      .then(response => response.json())
      .then(data => {
        this.setState({ vacancies: data, loading: false });
      });
  }

  handleDelete(id) {
    // 使用 prevState 确保基于最新状态修改,避免竞态问题
    this.setState(prevState => ({
      vacancies: prevState.vacancies.filter(v => v.id !== id)
    }));
  }

  render() {
    const { vacancies, loading } = this.state;
    return (
      <div>
        <Counter vacancies={vacancies} />
        {loading ? <p><em>Loading...</em></p> : <Vacancy vacancies={vacancies} onDelete={this.handleDelete} />}
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById('root'));

2. 修改 vacancies.jsx 为纯展示组件

去掉内部状态,通过 props 接收职位列表和删除方法:

import React from 'react';

export class Vacancy extends React.Component {
  render() {
    const { vacancies, onDelete } = this.props;
    return (
      <table className='table table-striped'>
        <thead>
          <tr>
            <th>Title</th>
            <th>Min Salary</th>
            <th>Max Salary</th>
          </tr>
        </thead>
        <tbody>
          {vacancies.map(v => (
            <tr key={v.id}>
              <td>{v.title}</td>
              <td>{v.currency} {v.minSalary}</td>
              <td>{v.currency} {v.maxSalary}</td>
              <td>
                <a href="#" onClick={(e) => {
                  e.preventDefault(); // 阻止默认页面跳转行为
                  onDelete(v.id);
                }}>Delete</a>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    );
  }
}

3. 修改 counter.jsx 接收 props 展示数据

同样去掉继承,通过 props 获取职位列表并展示长度:

import React from 'react';

export class Counter extends React.Component {
  render() {
    const { vacancies } = this.props;
    return (
      <div>
        <h1>Items:{vacancies.length}</h1>
      </div>
    );
  }
}

为什么这样能解决问题?

  • 状态提升到父组件后,Vacancy 和 Counter 共用同一个职位列表数据源
  • 当父组件的状态更新时,两个子组件会自动接收到更新后的 props,触发重新渲染,计数器数值也就同步变化了
  • 补充了 e.preventDefault() 避免点击删除链接时页面跳转
  • 把异步请求放到 componentDidMount 是 React 官方推荐的异步操作时机,比在 constructor 里更规范

如果后续组件层级变深,也可以用 React Context 来管理共享状态,但当前场景下状态提升是最简单直接的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:02:09