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
相关产品推荐
相关产品推荐

