2017-06-05 51 views
0

編寫一個名爲Member的組件,我正在做一些計算,我在this.state之前將它存儲到其他地方,但是我遇到了一個問題,當啓動一個onChange處理程序時,一些狀態值是undefined,但應填寫一些值。
狀態值state onChange

元器件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。我不知道爲什麼會發生。也許你可以給我一些建議?

+0

如果你的'setState'需要讀取以前的狀態,你的分量經常更新,建議使用' setState(updaterFunction)'API以確保您始終獲得最新狀態。 https://facebook.github.io/react/docs/react-component.html#setstate –

+0

在分配它之前,請確保您的事件參數不是未定義的(並且與您的應用程序的界限一致)。 – Storm

回答

1

看起來你所有的嵌套狀態都遇到了問題,即嵌套在project_data中。組件只是一次性更新子元素,即在第一次按鍵時以及後續的所有按鍵上,它不會更新任何內容,相反,對於非常奇怪的嵌套狀態項,值未定義。解決此問題的方法就像您可以將所有嵌套狀態項目移動爲單個級別狀態項目一樣。 例如:

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

,而不是您可以在子項移動到父

this.state = {    
      project_data_hourly_rate: 40 
    } 
+0

謝謝,我想到了這一點,但也認爲應該是最簡單的方式來更新嵌套狀態,遺憾的是不是。所以我會用你的變種來解決問題 – vladja

1

可以部分地更新狀態對象的頂級屬性,但嵌套的更新將無法正常工作。

immutability-helperupdate(更換react-addons-update)可用於更新嵌套屬性:

import update from 'immutability-helper'; 

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

謝謝你的回答,這很好,但我認爲我會選擇另一個作爲答案。主要原因是因爲我不想再添加一個依賴項 – vladja

+0

不客氣。然後使用這種技術,當你的狀態變得更加複雜時,當一個簡單的扁平結構是不夠的時候。 – m1kael