状态onChange的状态值`undefined`

时间:2017-06-05 13:33:48

标签: javascript reactjs state

编写一个名为Member的组件,我正在进行一些计算,我将它存储在this.state中,然后再将其发送到其他地方,但是在解雇一个onChange处理程序时遇到了问题某些状态值为undefined,但应填充一些值。

组件Member

import React from "react";

import {calcSCR, difference, multiply} from "../../utils/Calculations";
import {SCR_COEFF} from "../../constants/calc";

class Member extends React.Component {

    constructor(props){
        super(props);

        this.state = {
            id: "1",
            full_name: 'Mocked member 1',
            role: 'Developer',
            salary: 1650,
            hourly_cost: 19.6, // SCR = (gross * coeff) / 100
            project_data: {
                project_id: '1',
                hourly_rate: 40,
                occupation: 50,
                estimate_hours: 70,
                revenue: 2800,// revenue = estimate_hours * hourly_rate
                cost: 1372,// cost = estimate_hours * hourly_cost
                profit: 1428// profit = revenue - cost
            }
        };

        this.onSalaryChange = this.onSalaryChange.bind(this);
        this.onHourlyCostChange = this.onHourlyCostChange.bind(this);
        this.onHourlyRateChange = this.onHourlyRateChange.bind(this);
        this.onEstimateHoursChange = this.onEstimateHoursChange.bind(this);
        this.onRevenueChange = this.onRevenueChange.bind(this);
        this.onCostChange = this.onCostChange.bind(this);
        this.onNameChange = this.onNameChange.bind(this);
        this.onOccupationChange = this.onOccupationChange.bind(this);

        this.save = this.save.bind(this);

    }

    save(){

    }

    onNameChange(e){
        this.setState({
            full_name: e.target.value
        })
    }

    onSalaryChange(e){
        let salary = e.target.value;

        this.setState({
            salary: salary,
            hourly_cost: calcSCR(salary, SCR_COEFF)
        })
    }

    onHourlyRateChange(e){
        let hourly_rate = e.target.value;
        let estimate_hours = this.state.project_data.estimate_hours;

        this.setState({
            project_data: {
                hourly_rate: hourly_rate,
                revenue: multiply(estimate_hours, hourly_rate)
            }
        })

    }

    onOccupationChange(e){
        this.setState({
            project_data: {
                occupation: e.target.value
            }
        })
    }

    onEstimateHoursChange(e){
        let estimate_hours = e.target.value;

        this.setState({
            project_data: {
                estimate_hours: estimate_hours,
                revenue: multiply(estimate_hours, this.state.project_data.hourly_rate),
                cost: multiply(estimate_hours,this.state.hourly_cost)
            }
        })

    }

    onHourlyCostChange(e){
        let hourly_cost = e.target.value;
        this.setState({
            hourly_cost: hourly_cost,
            project_data: {
                cost: multiply(this.state.project_data.estimate_hours, hourly_cost)
            }
        })
    }

    onRevenueChange(e){

        let revenue = e.target.value;

        this.setState({
            project_data: {
                revenue: revenue,
                profit: difference(revenue,this.state.project_data.cost)
            }
        })
    }

    onCostChange(e){

        let cost = e.target.value;

        this.setState({
            project_data: {
                cost: cost,
                profit: difference(this.state.project_data.revenue,cost)
            }
        })
    }

    render(){

        let {projectName} = this.props;
        let data = this.state;

        return (
            <div className="member">
                <a className="member__short_info" role="button" data-toggle="collapse" href={`#${data.id}`} aria-expanded="false" aria-controls={data.id}>
                    {data.full_name}
                </a>

                <div className="collapse member__member_full_info" id={data.id}>
                    <div className="member__full_info__row">
                        <div className="row">
                            <div className="col-sm-12 col-md-12 com-lg-12 member__full_info__header">
                                {projectName}
                            </div>

                            <div className="col-sm-12 col-md-12 col-lg-6 member__full_info__column">
                                <label htmlFor="full_name" className="member__full_info__label">Member full name:</label>
                                <input id="full_name" type="text" name="full_name" value={data.full_name} onChange={this.onNameChange}/>
                            </div>

                            <div className="col-sm-12 col-md-12 col-lg-6 member__full_info__column">
                                <label htmlFor="salary" className="member__full_info__label">Salary:</label>
                                <input id="salary" type="text" name="salary" value={data.salary} onChange={this.onSalaryChange}/>
                            </div>

                            <div className="col-sm-12 col-md-12 col-lg-6 member__full_info__column">
                                <label className="member__full_info__label">Hourly cost: </label>
                                <input id="hourly_cost" type="text" name="hourly_cost" value={data.hourly_cost} onChange={this.onHourlyCostChange}/>
                            </div>

                            <div className="col-sm-12 col-md-12 col-lg-6 member__full_info__column">
                                <label htmlFor="hourly_rate" className="member__full_info__label">Hourly rate</label>
                                <input id="hourly_rate" type="text" name="hourly_rate" value={data.project_data.hourly_rate} onChange={this.onHourlyRateChange}/>
                            </div>

                            <div className="col-sm-12 col-md-12 col-lg-6 member__full_info__column">
                                <label htmlFor="occupation" className="member__full_info__label">Occupation in project (%): </label>
                                <input id="occupation" type="text" name="occupation" value={data.project_data.occupation} onChange={this.onOccupationChange}/>
                            </div>

                            <div className="col-sm-12 col-md-12 col-lg-6 member__full_info__column">
                                <label htmlFor="estimate_hours" className="member__full_info__label">Estimate hours: </label>
                                <input id="estimate_hours" type="text" name="estimate_hours" value={data.project_data.estimate_hours} onChange={this.onEstimateHoursChange}/>
                            </div>

                            <div className="col-sm-12 col-md-12 col-lg-4 member__full_info__column">
                                <label className="member__full_info__label">Revenue: {data.project_data.revenue}</label>
                                {/*<input id="revenue" type="number" name="revenue" value={data.project_data.revenue} onChange={this.onRevenueChange}/>*/}
                            </div>

                            <div className="col-sm-12 col-md-12 col-lg-4 member__full_info__column">
                                <label className="member__full_info__label">Cost: {data.project_data.cost}</label>
                                {/*<input id="cost" type="number" name="cost" value={data.project_data.cost} onChange={this.onCostChange}/>*/}
                            </div>

                            <div className="col-sm-12 col-md-12 col-lg-4 member__full_info__column">
                                <label className="member__full_info__label">Profit: {data.project_data.profit}</label>
                            </div>

                            <div className="col-sm-12 member__full_info__save">
                                <button className="modal-component positive-btn no-margin" onClick={this.save}>Save</button>

                            </div>

                        </div>
                    </div>
                </div>
            </div>


        );
    }
}

export default Member;

例如:内部onHourlyRateChange函数estimate_hours在更改后变为undefined

内部onEstimateHoursChange状态变量this.state.project_data.hourly_ratethis.state.project_data.hourly_cost也变为undefined。我不知道为什么会这样。也许你可以给我一些建议吗?

2 个答案:

答案 0 :(得分:1)

看起来所有嵌套状态都遇到问题,即嵌套在project_data中。组件只是一次更新子元素,即在第一次按键时和所有后续按键时,它没有更新任何内容,而是嵌套状态项的值未定义,这是非常奇怪的。解决此问题的方法就像您可以将所有嵌套状态项移动为单级状态项。 例如:

this.state = {            
            project_data: { hourly_rate: 40 }
    }

相反,您可以将子项目移动到父项

this.state = {            
            project_data_hourly_rate: 40
    }

答案 1 :(得分:1)

您可以部分更新状态对象的顶级属性,但嵌套更新将不起作用。

immutability-helperupdate(替换为react-addons-update)可用于更新嵌套属性:

import update from 'immutability-helper';

const newData = update(myData, {
  x: {y: {z: {$set: 7}}},
  a: {b: {$push: [9]}}
});