如何使用 setState 更新 state.item\[1\]?

新手上路,请多包涵

我正在创建一个应用程序,用户可以在其中设计自己的表单。例如,指定字段的名称和应包含的其他列的详细信息。

该组件 在此处 作为 JSFiddle 提供。

我的初始状态如下所示:

var DynamicForm = React.createClass({
  getInitialState: function() {
   var items = {};
   items[1] = { name: 'field 1', populate_at: 'web_start',
                same_as: 'customer_name',
                autocomplete_from: 'customer_name', title: '' };
   items[2] = { name: 'field 2', populate_at: 'web_end',
                same_as: 'user_name',
                    autocomplete_from: 'user_name', title: '' };

     return { items };
   },

  render: function() {
     var _this = this;
     return (
       <div>
         { Object.keys(this.state.items).map(function (key) {
           var item = _this.state.items[key];
           return (
             <div>
               <PopulateAtCheckboxes this={this}
                 checked={item.populate_at} id={key}
                   populate_at={data.populate_at} />
            </div>
            );
        }, this)}
        <button onClick={this.newFieldEntry}>Create a new field</button>
        <button onClick={this.saveAndContinue}>Save and Continue</button>
      </div>
    );
  }

我想在用户更改任何值时更新状态,但我很难定位正确的对象:

var PopulateAtCheckboxes = React.createClass({
  handleChange: function (e) {
     item = this.state.items[1];
     item.name = 'newName';
     items[1] = item;
     this.setState({items: items});
  },
  render: function() {
    var populateAtCheckbox = this.props.populate_at.map(function(value) {
      return (
        <label for={value}>
          <input type="radio" name={'populate_at'+this.props.id} value={value}
            onChange={this.handleChange} checked={this.props.checked == value}
            ref="populate-at"/>
          {value}
        </label>
      );
    }, this);
    return (
      <div className="populate-at-checkboxes">
        {populateAtCheckbox}
      </div>
    );
  }
});

我应该如何制作 this.setState 以使其更新 items[1].name

原文由 martins 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 816
2 个回答

以下是在没有帮助库的情况下如何做到这一点:

 handleChange: function (e) {
 // 1. Make a shallow copy of the items
 let items = [...this.state.items];
 // 2. Make a shallow copy of the item you want to mutate
 let item = {...items[1]};
 // 3. Replace the property you're intested in
 item.name = 'newName';
 // 4. Put it back into our array. NB we *are* mutating the array here,
 // but that's why we made a copy first
 items[1] = item;
 // 5. Set the state to our new copy
 this.setState({items});
 },

如果需要,您可以组合步骤 2 和 3:

 let item = {
 ...items[1],
 name: 'newName'
 }

或者您可以在一行中完成整个操作:

 this.setState(({items}) => ({
 items: [
 ...items.slice(0,1),
 {
 ...items[1],
 name: 'newName',
 },
 ...items.slice(2)
 ]
 }));

注意:我将 items 设为数组。 OP使用了一个对象。但是,概念是相同的。


您可以在终端/控制台中看到发生了什么:

 ❯ node
 > items = [{name:'foo'},{name:'bar'},{name:'baz'}]
 [ { name: 'foo' }, { name: 'bar' }, { name: 'baz' } ]
 > clone = [...items]
 [ { name: 'foo' }, { name: 'bar' }, { name: 'baz' } ]
 > item1 = {...clone[1]}
 { name: 'bar' }
 > item1.name = 'bacon'
 'bacon'
 > clone[1] = item1
 { name: 'bacon' }
 > clone
 [ { name: 'foo' }, { name: 'bacon' }, { name: 'baz' } ]
 > items
 [ { name: 'foo' }, { name: 'bar' }, { name: 'baz' } ] // good! we didn't mutate `items`
 > items === clone
 false // these are different objects
 > items[0] === clone[0]
 true // we don't need to clone items 0 and 2 because we're not mutating them (efficiency gains!)
 > items[1] === clone[1]
 false // this guy we copied

原文由 mpen 发布,翻译遵循 CC BY-SA 4.0 许可协议

您可以为此使用 update 不变性助手

 this.setState({
  items: update(this.state.items, {1: {name: {$set: 'updated field name'}}})
})

或者,如果您不关心使用 ===shouldComponentUpdate() 生命周期方法中检测此项的更改,您可以直接编辑状态并强制组件重新渲染- 这实际上与@limelights 的回答相同,因为它将对象拉出状态并对其进行编辑。

 this.state.items[1].name = 'updated field name'
this.forceUpdate()


编辑后补充:

查看 react-training 中的 简单组件通信 课程,了解如何将回调函数从状态保持父组件传递到需要触发状态更改的子组件。

原文由 Jonny Buchanan 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题