【问题标题】:Update state by changing an entire object within state array通过更改状态数组中的整个对象来更新状态
【发布时间】:2017-02-25 17:14:38
【问题描述】:

我正在尝试创建更新应用程序状态的输入行。该应用程序目前只有两个组件,TimeCalc 和 ItemsList。状态存储在 TimeCalc 中,ItemsList 处理条件渲染(显示状态或显示输入行。

我已设法获取已编辑和更新的对象,但我正在努力用状态中的正确对象替换更新的对象。对象包含道具_id、标题、开始和结束,最好我想搜索匹配的_id,并替换状态中的整个对象。但是看到 _id 道具是其他道具的兄弟道具,我不知道该怎么做。

这是时间计算器:

import React from 'react';
import ItemsList from '../components/ItemsList';
const items = [
 {
    _id: '112233',
    title: 'M1',
    start: 900,
    end: 1800
  },
  {
    _id: '223344',
    title: 'M2',
    start: 1000,
    end: 1900
  }
];
export default class TimeCalc extends React.Component {
  state = {
    items
  }
  handleUpdate = (update) => {

  }
  render = () => {
    return (
      <div class="timeCalc flex center">
        <ItemsList items={this.state.items} handleUpdate={this.handleUpdate}/>
      </div>
    )
  }
}

这里是 ItemsList:

import React from 'react';
export default class ItemsList extends React.Component {
  state = {
    editing: null
  }
  toggleEditing = (itemId) => {
    this.setState({
      editing: itemId
    })
  }
  handleEditItem = () => {
    let itemId = this.state.editing;
    this.handleItemsUpdate({
      _id: itemId,
      title: this.refs[`title_${itemId}`].value,
      start: this.refs[`start_${itemId}`].value,
      end: this.refs[`end_${itemId}`].value,
    })
  }
  handleItemsUpdate = (update) => {
    console.log(update);
    this.props.handleUpdate(update);
    this.setState( { editing: null } );
  }
  renderItemOrEditField = (item) => {
    if(this.state.editing === item._id) {
      return <li key={`editing-${item._id} `} class="list-item flex row">
        <input
          onKeyDown={this.handleEditField}
          type="text"
          class="form-input"
          ref={`title_${item._id}`}
          name="title"
          defaultValue={item.title}
          />
        <input
          onKeyDown={this.handleEditField}
          type="text"
          class="form-input"
          ref={`start_${item._id}`}
          name="start"
          defaultValue={item.start}
          />
        <input
          onKeyDown={this.handleEditField}
          type="text"
          class="form-input"
          ref={`end_${item._id}`}
          name="end"
          defaultValue={item.end}
          />
          <button onClick={this.handleEditItem} label="Update Item"/>
        </li>
    } else {
      return <li
        onClick = {this.toggleEditing.bind(null, item._id)}
        key = {item._id}
        class = "list-position">
        {` ${item.title} & ${item.start} && ${item.end} && ${item._id}`}
        </li>
    }
  }
  render = () => {
    return (
      <ul class="itemsList">
        {this.props.items.map((item) => {
          return this.renderItemOrEditField(item);
        })}
    </ul>
    )
  }
}

我正在尝试重新创建 MeteorChef 的“单击以编辑 React 中的字段”,但他正在以 Meteor 方式存储状态。

【问题讨论】:

    标签: reactjs state


    【解决方案1】:

    我建议您将所有状态移动到父组件。保持 ItemsList 无状态可以更整齐地分离您的关注点,并使代码更易于推理。在这种情况下,所有 ItemsList 都需要关注的是根据存储在父级中的状态呈现数据。在您的 TimeCalc 组件中,为状态对象添加一个“编辑”键,并添加一个方法来处理来自 ItemsList 的更新:

    state = {
      items,
      editing: null,
    }
    
    handleUpdate = (editing) => {
      this.setState({ editing });
    }
    

    然后在渲染子组件时,将这个处理函数、items数组和“editing”键作为props传递:

    <ItemsList items={this.state.items} editing={this.state.editing} handleUpdate={this.handleUpdate}/>
    

    现在ItemsList可以变成一个无状态的功能组件,像这样:

    import React from 'react';
    
    const renderItemOrEditField = (item, editing, handleUpdate) => (
      {editing === item._id ? (
        <li key={item._id} className="list-item flex row">
          <input onKeyDown={handleUpdate(item._id}
          // The rest of your content to render if item is being edited
      ) : (
        // content to be rendered if item isn't being edited goes here
      )}
    );
    
    export default const ItemsList = (props) => (
      <ul className="itemsList">
        {props.items.map((item) => {
          return renderItemOrEditField(item, props.editing, props.handleUpdate);
        })}
      </ul>
    );
    

    这种使用管理状态和业务逻辑的“智能”容器组件以及“哑”表示组件的策略可以大大提高您的应用程序的可维护性和不那么脆弱。希望这会有所帮助!

    【讨论】:

    • 亲爱的唐尼,非常感谢您抽出宝贵的时间!我设法用以下代码解决了这个问题: handleUpdate = (update) => { let r = this.state.items.map(x => x._id === update._id ? update : x) this.setState ({项目:r});确实只是用更新的项目替换 this.state.items 。像魅力一样工作:) 我考虑过让组件无状态和有状态,但主要组件将非常难以维护,因为它也在更新来自不同组件的状态。如果应用程序不断增长,我应该考虑 redux/flux...
    猜你喜欢
    • 2016-01-02
    • 2020-07-01
    • 2022-01-06
    • 2016-10-06
    • 2019-05-17
    • 2015-11-21
    • 2021-12-26
    • 1970-01-01
    • 2019-11-22
    相关资源
    最近更新 更多