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

React问题:Props变更时孙组件未重新渲染值

问题解决:费率类型变更时已选员工费率不更新

问题根源

你的Breakdown组件仅在组件挂载和选择员工类型时调用updateRate计算费率,但当父组件传递的rateType props发生变化时,组件没有监听这个变更并重新计算费率,导致已选中员工的费率无法同步更新。

解决方案

添加componentDidUpdate生命周期函数,监听rateType props的变化,一旦检测到变更就重新执行updateRate,更新当前员工的费率:

// 在组件中添加以下生命周期函数
componentDidUpdate(prevProps) {
  // 仅当rateType发生变化时执行更新
  if (prevProps.rateType !== this.props.rateType) {
    this.updateRate();
  }
}

完整修改后的组件代码

import React, { Component } from 'react';
import {Form} from 'react-bootstrap';
import styled from 'styled-components';
import { config } from '../../Config/Constants';
import debounce from 'lodash.debounce';

const API_URL = config.url.API_URL;

const Div = styled.div`
    color: black;
`

class Breakdown extends Component {
    constructor(props) {
        super(props);

        this.state = {
            employee_type: "Choose",
            employee_name: "Choose",
            rate: 0,
            cost: 0,
            hours1: 0,
            hours2: 0,
            hours3: 0,
            total_hours: 0,
            total_costs: 0,
            total_bill: 0,
            margin: 0,

            // Cost Chart
            employeeTable: [
                { name: "Choose", cost: 0, type:"Choose"},
                { name: "Adam N", cost: 95.53, type: "Executive" },
                { name: "Amber H", cost: 50.33, type: "Senior" },
                { name: "Denise M", cost: 28.34, type: "Coordinator" }
            ],

            // Rate Charts
            rateChartNonProfit: [
                { type: "Choose", rate: 0 },
                { type: "Executive", rate: 300 },
                { type: "Senior", rate: 250 },
                { type: "Mid-Level", rate: 200 },
                { type: "Associate", rate: 150 },
                { type: "Coordinator", rate: 150 }
            ], 
            rateChartForProfit: [
                { type: "Choose", rate: 0 },
                { type: "Executive", rate: 400 },
                { type: "Senior", rate: 275 },
                { type: "Mid-Level", rate: 225 },
                { type: "Associate", rate: 175 },
                { type: "Coordinator", rate: 175 }
            ], 
            rateChartExisting: [
                { type: "Choose", rate: 0 },
                { type: "Executive", rate: 400 },
                { type: "Senior", rate: 275 },
                { type: "Mid-Level", rate: 225 },
                { type: "Associate", rate: 175 },
                { type: "Coordinator", rate: 175 }
            ]
        }
    }

    componentDidMount() {
        this.getBreakdownData(this.props.breakdownId);
    }

    // 添加这个生命周期函数
    componentDidUpdate(prevProps) {
        if (prevProps.rateType !== this.props.rateType) {
            this.updateRate();
        }
    }

    getBreakdownData(breakdownId) {
        fetch(API_URL + `/billingcalculator/${breakdownId}`)
            .then((res) => {
                if (!res.ok) {
                    throw new Error()
                }
                return res.json()
            })
            .then((result) => {
                this.setState({ ...result[0], });
            })
            .catch((error) => {
                console.log(error);
            })
            .then(() => this.updateRate()); // 修正异步调用问题
    }

    selectType = (e) => {
        this.setState({ employee_type: e.target.value },
        () => this.updateRate()
        )
    }

    selectEmployee = (e) => {
        // 补充缺失的员工选择逻辑,更新对应成本
        const selectedEmployee = this.state.employeeTable.find(emp => emp.name === e.target.value);
        this.setState({ 
            employee_name: e.target.value,
            cost: selectedEmployee?.cost || 0
        });
    }

    handleChange = (e) => {
        // 补充缺失的工时输入逻辑,更新工时并计算总工时
        const { name, value } = e.target;
        this.setState({ [name]: parseFloat(value) || 0 }, () => {
            this.updateTotals();
        });
    }

    updateRate() {
        let rateType = this.props.rateType;
        let targetChart;
        // 简化费率表选择逻辑
        switch(rateType) {
            case "non-profit":
                targetChart = this.state.rateChartNonProfit;
                break;
            case "existing":
                targetChart = this.state.rateChartExisting;
                break;
            default:
                targetChart = this.state.rateChartForProfit;
        }
        const matchedRate = targetChart.find(item => item.type === this.state.employee_type);
        this.setState({ rate: matchedRate?.rate || 0 }, () => this.updateTotals());
    }

    updateTotals() {
        // 补充缺失的计算逻辑,计算总工时、成本、账单和利润
        const { hours1, hours2, hours3, rate, cost } = this.state;
        const totalHours = hours1 + hours2 + hours3;
        const totalCosts = totalHours * cost;
        const totalBill = totalHours * rate;
        const margin = totalBill - totalCosts;

        this.setState({
            total_hours: totalHours,
            total_costs: totalCosts,
            total_bill: totalBill,
            margin: margin
        });
    }

    render() {
        return (
            <tr key={this.props.breakdownId}>
                <td>
                    <select name="employee_type" value={this.state.employee_type} onChange={this.selectType}>
                        <option value="Choose">Choose</option>
                        <option value="Executive">Executive</option>
                        <option value="Senior">Senior</option>
                        <option value="Mid-Level">Mid-Level</option>
                        <option value="Associate">Associate</option>
                        <option value="Coordinator">Coordinator</option>
                    </select>
                </td>
                <td>
                    <select name="employee_name" value={this.state.employee_name} onChange={this.selectEmployee}>
                        <option value="Choose">Choose</option>
                        <option value="Adam N">Adam N</option>
                        <option value="Amber H">Amber H</option>
                        <option value="Denise M">Denise M</option>
                    </select>
                </td>
                <td>
                    {this.state.rate}
                </td>
                <td>
                    {this.state.cost}
                </td>
                <td>
                    <Form.Control
                        size="sm"
                        type="text"
                        value={this.state.hours1}
                        onChange={this.handleChange}
                        name="hours1"
                    />
                </td>
                <td>
                    <Form.Control
                        size="sm"
                        type="text"
                        value={this.state.hours2}
                        onChange={this.handleChange}
                        name="hours2"
                    />
                </td>
                <td>
                    <Form.Control
                        size="sm"
                        type="text"
                        value={this.state.hours3}
                        onChange={this.handleChange}
                        name="hours3"
                    />
                </td>
                <td>
                    {this.state.total_hours}
                </td>
                <td>
                    {this.state.total_costs}
                </td>
                <td>
                    {this.state.total_bill}
                </td>
                <td>
                    {this.state.margin}
                </td>
            </tr>        
        )
    }
}

export default Breakdown;

额外优化说明

  1. 修复了getBreakdownData中异步调用updateRate的错误写法,避免函数立即执行
  2. 补充了原代码缺失的selectEmployee、handleChange、updateTotals函数,保证功能完整性
  3. 简化了updateRate中的费率表选择逻辑,提升代码可读性和维护性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 02:45:32