2016-09-17 44 views
0

我正在學習ReactJS,並在管理我的對象狀態時遇到了一些問題。我在下面描述了我想要做的和我採取的方法。如何管理ReactJS中JSON對象的某些屬性的狀態?

一般的想法是,我從REST服務接收到複雜的JSON對象。這個較大的JSON對象的屬性之一是「保留」,它代表某天某個項目的預留。預留對象具有屬性「項目」,「小時」(它們將被修改)和「availableProjects」列表。可用項目將通過下拉菜單顯示,用戶可以選擇它來更新屬性「reservation.project」。填充完所有預留,小時和其他一些屬性後,我想將這個修改過的對象發送回服務器。

這裏是代碼:

var ReservationBox = React.createClass({ 
getInitialState: function() { 
    return { 
     reservation: this.props.reservation //IS THIS ANTI-PATTERN ? 
    } 
}, 
onSelectProject: function (selectedProject) { 
    this.setState({reservation: {project: selectedProject}}); // IT WORKS but I don't know I did it correctly according to best practices :-) 
}, 
handleHoursChange: function (e) { 
    this.setState({reservation: {hours: e.target.value}}) // THIS DOES NOT WORK 
}, 
render: function() { 
    return (
     <div> 
      {this.state.name} 
      <div className="btn-group timesheet-project-column"> 
       <button type="button" 
         className="btn btn-primary">{this.state.reservation.project.projectName}</button> 
       <button type="button" className="btn btn-primary dropdown-toggle" data-toggle="dropdown" 
         aria-haspopup="true" aria-expanded="false"> 
        <span className="caret"></span> 
        <span className="sr-only">Toggle Dropdown</span> 
       </button> 
       <AvailableProjectsListBox reservation={this.state.reservation} 
              onSelectProject={this.onSelectProject}/> 
      </div> 
      <div className="timesheet-column"> 
       <button type="button" className="btn btn-default"> 
        <span className="glyphicon glyphicon-pencil"/> 
       </button> 
      </div> 
      <div className="timesheet-column"> 
       <input type="text" className="form-control timesheet-hour" 
         value={this.state.reservation.hours} 
         onChange={this.handleHoursChange}/> 
      </div> 
      <div className="timesheet-column"> 
       <button type="button" className="btn btn-danger"> 
        <span className="glyphicon glyphicon-trash img-circle text-danger"></span> 
       </button> 
      </div> 
     </div> 
    ); 
} 
}); 


var AvailableProjectsListBox = React.createClass({ 
    render: function() { 
     var onSelectProject = this.props.onSelectProject; 
     var availableProjects = this.props.reservation.availableProjects.map(function (availableProject) { 
      return (
       <AvailableProject availableProject={availableProject}  
onSelectProject={onSelectProject}/> 
      ); 
     }); 
     return (
      <ul className="dropdown-menu"> 
       {availableProjects} 
      </ul> 
     ); 
    } 
}); 

var AvailableProject = React.createClass({ 
    handleSelectProject: function() { 
     this.props.onSelectProject(this.props.availableProject.project); 
    }, 
    render: function() { 
     return (
      <li><a href="#" onClick={this.handleSelectProject}> 
       {this.props.availableProject.project.projectName}</a> 
      </li> 
     ); 
    } 
}); 

我不能修改輸入 「小時」 - 它保持初始值。我的方法有什麼問題?如何處理這種情況,我有大的JSON對象,其中許多部分不會被修改(所以我將它們作爲道具傳遞給嵌套組件),並且一些屬性需要修改狀態?

編輯:現在它按照我的預期工作,但我認爲更新JSON作爲「道具」傳遞是個壞主意,它必須是更好的方式來做到這一點,但最後我保持我的狀態'項目'和'小時'同步與JSON'保留'對象。

var ReservationBox = React.createClass({ 
    getInitialState: function() { 
     return { 
      projectName: this.props.reservation.project.projectName, 
      hours: this.props.reservation.hours 
     } 
    }, 
    onSelectProject: function (selectedProject) { 
     this.setState({projectName: selectedProject.projectName}); 
     this.props.reservation.project = selectedProject; 
    }, 
    handleHoursChange: function (e) { 
     this.setState({hours: e.target.value}) 
     this.props.reservation.hours = e.target.value; 
    }, 
    render: function() { 
     return (
      <div> 
       <div className="btn-group timesheet-project-column"> 
        <button type="button" 
          className="btn btn-primary">{this.state.projectName}</button> 
        <button type="button" className="btn btn-primary dropdown-toggle" data-toggle="dropdown" 
          aria-haspopup="true" aria-expanded="false"> 
         <span className="caret"></span> 
         <span className="sr-only">Toggle Dropdown</span> 
        </button> 
        <AvailableProjectsListBox reservation={this.props.reservation} 
               onSelectProject={this.onSelectProject}/> 
       </div> 
       <div className="timesheet-column"> 
        <button type="button" className="btn btn-default"> 
         <span className="glyphicon glyphicon-pencil"/> 
        </button> 
       </div> 
       <div className="timesheet-column"> 
        <input type="text" className="form-control timesheet-hour" 
          value={this.state.hours} 
          onChange={this.handleHoursChange}/> 
       </div> 
       <div className="timesheet-column"> 
        <button type="button" className="btn btn-danger"> 
         <span className="glyphicon glyphicon-trash img-circle text-danger"></span> 
        </button> 
       </div> 
      </div> 
     ); 
    } 
}); 
+0

你能否詳細說明*「這不起作用」*的意思?它會在控制檯中拋出一個錯誤,還是隻是在默默地失敗? – ivarni

+0

value = {this.state.reservation.hours} onChange = {this.handleHoursChange} />「保留默認值,即分配給我的輸入字段」input type =「text」className =「form-controltimesheet-hour」 在getInitialState中。當我輸入新的時候,默認會立即覆蓋它。 –

+0

你想更新數據庫中的時間嗎?或者你想保持本地? – jacoballenwood

回答

0

你是正確的,這是一種做事的「壞」的方式:如果有人經歷了陣營給我一些提示如何正確地做,我將不勝感激。

在React中,道具和狀態都不應該直接修改。他們被認爲是不可變的。你可以直接改變它們(就像你已經做的那樣),但是它干擾了React處理它重新渲染循環的方式,並且你冒着1.不更新你應該或者2.當道具被覆蓋父組件。

然而,反應過來的時候,你需要通過this.setState({})給你修改國家所需要的工具。只需使用該方法,而不是直接更改數據。

你已經做的第一行本的handleHoursChange內。第二行只是需要刪除。

如果你需要傳遞的東西上游組件的父,做正確的做法是通過在一個函數傳遞作爲道具的孩子之一。一個簡單的例子可能是這樣的;

var ReservationBoxParent = React.createClass({ 
    handleChange: function(hours){ 
     //do something with hours here 
    }, 
    render: function(){ 
     return <ReservationBox onChange={this.handleChange} reservation={this.props.reservation}/>; 
    } 
}); 

var ReservationBox = React.createClass({ 
    getInitialState: function(){ 
     return {hours: this.props.reservation.hours} 
    }, 
    handleHoursChange: function(hours){ 
     this.setState({hours: hours}); 
     this.props.onChange({hours: hours}); 
    }, 

    render: function(){ 
     return <input type="text" 
          value={this.state.hours} 
          onChange={this.handleHoursChange}/> 
    } 
}); 
+0

感謝您的回答,現在我理解了狀態和概念道具在組件中,但在ReservationBox組件中設置小時的狀態只會更新視圖(它反映了ReservationBox的當前狀態),我想更新從服務器獲取的全局JSON對象。我認爲它是我從服務器獲得的一些「商店」,用戶可以修改它,用戶可以做很多修改,其中一個是設置小時,選擇項目,但還有很多其他輸入可以修改。在這些修改之後,我想將這個對象發送到服務器以在數據庫中進行更新。 .. –

+0

正如我在反應調試器中看到的,只有反應組件的'狀態'屬性被更新,但現在我想更新我的JSON obj(現在我通過更新道具來做它,但它是壞的)。我已經閱讀過關於全球商店和圖書館的概念,但最初我想用純粹的反應來理解它是如何工作的。 –

+0

在ReservationBoxParent中,我應該做些什麼來更新函數'handleChange'中的'this.props.reservation.hours = hours'? –

相關問題