2016-09-17 66 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'? –

相关问题