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

React更新state数组后子组件UI未同步更新的问题排查

问题原因

子组件的expenseData状态仅在组件首次挂载时通过构造函数从props.data初始化,后续父组件更新dataSource导致props.data变化时,子组件没有同步更新state.expenseData的逻辑,因此this.state.expenseData.ValidFlag始终显示初始化时的旧值;而this.props.validFlag直接读取父组件传递的最新props,所以能正常更新。

解决方案

方案1:直接使用Props(推荐)

如果子组件仅需展示数据、不需要独立维护状态,完全可以直接使用this.props.data替代this.state.expenseData,无需将props存入state。

修改后的子组件代码:

import React, { Component } from "react";
import '../../CompCss/ExpenseEditableBlock.css';
import 'react-dropdown/style.css';
import { Utils } from './../Utils';

const utils = Utils();

class ExpenseEditableBlock extends Component {
    constructor(props){
        super(props);
        this.state = {
            categoryArray: utils.expCategories().map(item => item.label),
            _otherVarName_ : null,
            checked: false
        }
    }

  render() {
    const { data } = this.props;
    return (
      <div className={(data.ValidFlag === "FAIL")?"exp-block-box-one disabled-item":"exp-block-box-one"} style={this.props.style}>
        <div id="exp-item-head-section">
            <div className="display-inline-block">
                <p>Trx ID: {data.TrxID}</p>
                <p>{data.ValidFlag}</p>  {/* 现在会随props更新 */}
                <p>{this.props.validFlag}</p>
            </div>
        </div>
        <div>
            <div className="exp-date-block">{data.TrxDate}</div>
            <div>
                <p>{data.TrxTitle}</p>
            </div>
        </div>
        
        <div style={{height: '3px'}}>
            {/* <TextField id="standard-basic" label="Standard" variant="standard" /> */}
        </div>
      </div>
    )
  }
}

export default ExpenseEditableBlock;

方案2:同步Props到State(当子组件需要独立维护状态时)

如果子组件需要修改expenseData并维护自己的状态,需在props变化时主动同步到state。可以使用componentDidUpdate或getDerivedStateFromProps:

方式1:使用componentDidUpdate

import React, { Component } from "react";
import '../../CompCss/ExpenseEditableBlock.css';
import 'react-dropdown/style.css';
import { Utils } from './../Utils';

const utils = Utils();

class ExpenseEditableBlock extends Component {
    constructor(props){
        super(props);
        this.state = {
            expenseData: props.data,
            categoryArray: utils.expCategories().map(item => item.label),
            _otherVarName_ : null,
            checked: false
        }
    }

    // 当props更新时同步state
    componentDidUpdate(prevProps) {
        if (prevProps.data !== this.props.data) {
            this.setState({ expenseData: this.props.data });
        }
    }

  render() {
    return (
      <div className={(this.state.expenseData.ValidFlag === "FAIL")?"exp-block-box-one disabled-item":"exp-block-box-one"} style={this.props.style}>
        <div id="exp-item-head-section">
            <div className="display-inline-block">
                <p>Trx ID: {this.state.expenseData.TrxID}</p>
                <p>{this.state.expenseData.ValidFlag}</p>  {/* 现在会同步更新 */}
                <p>{this.props.validFlag}</p>
            </div>
        </div>
        <div>
            <div className="exp-date-block">{this.state.expenseData.TrxDate}</div>
            <div>
                <p>{this.state.expenseData.TrxTitle}</p>
            </div>
        </div>
        
        <div style={{height: '3px'}}>
            {/* <TextField id="standard-basic" label="Standard" variant="standard" /> */}
        </div>
      </div>
    )
  }
}

export default ExpenseEditableBlock;

方式2:使用getDerivedStateFromProps(更符合React规范)

import React, { Component } from "react";
import '../../CompCss/ExpenseEditableBlock.css';
import 'react-dropdown/style.css';
import { Utils } from './../Utils';

const utils = Utils();

class ExpenseEditableBlock extends Component {
    constructor(props){
        super(props);
        this.state = {
            expenseData: props.data,
            categoryArray: utils.expCategories().map(item => item.label),
            _otherVarName_ : null,
            checked: false
        }
    }

    // 静态方法,在props变化时计算新的state
    static getDerivedStateFromProps(nextProps, prevState) {
        if (nextProps.data !== prevState.expenseData) {
            return { expenseData: nextProps.data };
        }
        return null; // 无需更新state时返回null
    }

  render() {
    return (
      <div className={(this.state.expenseData.ValidFlag === "FAIL")?"exp-block-box-one disabled-item":"exp-block-box-one"} style={this.props.style}>
        <div id="exp-item-head-section">
            <div className="display-inline-block">
                <p>Trx ID: {this.state.expenseData.TrxID}</p>
                <p>{this.state.expenseData.ValidFlag}</p>  {/* 现在会同步更新 */}
                <p>{this.props.validFlag}</p>
            </div>
        </div>
        <div>
            <div className="exp-date-block">{this.state.expenseData.TrxDate}</div>
            <div>
                <p>{this.state.expenseData.TrxTitle}</p>
            </div>
        </div>
        
        <div style={{height: '3px'}}>
            {/* <TextField id="standard-basic" label="Standard" variant="standard" /> */}
        </div>
      </div>
    )
  }
}

export default ExpenseEditableBlock;
额外注意点
  • 初始化categoryArray时,不要直接用this.state.categoryArray.push(...)修改state,应该在构造函数中直接通过map生成新数组赋值,避免直接修改state导致的不可预测问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 21:57:34