在另一个数组内部的对象内部的数组中对更新状态做出反应

时间:2020-03-24 17:54:39

标签: reactjs

我正在尝试在任务列表上分别为每个人添加一个新任务。我成功获取了每个人的ID,并在addItem函数中向该人信息数组添加了新任务,当我登录控制台时,我什至可以看到我的新状态被更新为正确的值。但是,我收到此错误->无法读取未定义的属性“地图”。另外,在这种情况下更新状态的最佳方法是什么?我知道散布运算符或Object.assign被大量使用,但是当存在嵌套的状态级别时,我应该怎么想?

class App extends React.Component {
  state = {
    data: [
      {
        id: 0,
        title: "Winnie",
        info: [
          "Buy eggs from the grocery store",
          "Return text books to the campus",
          "Buy eggs from the grocery store",
          "Return text books to the campus"
        ]
      },
      {
        id: 1,
        title: "Maggie",
        info: [
          "Finish cleaning before 11 pm",
          "See if Michael has any recommendations",
          "Buy eggs from the grocery store",
          "Return text books to the campus"
        ]
      }
  };

  addItem = id => {
    const enteredTask = prompt("Please enter a task");

    this.state.data.map(d => {
      if (d.id == id) {
        d.info = [...d.info, enteredTask];
        console.log("d info", d);
        this.setState({
          data: [...this.state.data, d.info]
        });
        console.log("state is", this.state.data);
      }
    });
  };

  render() {
    return (
      <div>
        <h3 className="header">Dashboard</h3>
        <div className="card-parent">
          {this.state.data.map(d => {
            return <Card key={d.id} info={d} addItem={this.addItem} />;
          })}
        </div>
      </div>
    );
  }
}



class Card extends React.Component {
  render() {
    return (
      <div className="card-style">
        <h4 className="card-header">{this.props.info.title}</h4>
        {this.props.info.info.map(i => {
          return <p className="card-info">{i}</p>;
        })}
        <button
          onClick={() => this.props.addItem(this.props.info.id)}
          className="card-button"
        >
          Add New Task
        </button>
      </div>
    );
  }
}

3 个答案:

答案 0 :(得分:1)

此错误可能来自:渲染函数内部的this.props.info.info.map。我认为您原打算改为this.props.info.map

理想情况下,您可以执行this.props.info && this.props.info.map。 只需确定代码中包含的数组,然后再映射它,就首先要检查它是否存在。在映射代码中的任何数组之前执行此操作

// for any array named arr
arr && arr.map(//your operation)

即使arr = []也没有元素,也就是将其类型转换为布尔值时仍然为真。

关于第二部分,传播运算符 Object.assign 的思想是更改引用,从而对更新状态做出反应。

但是请注意,这两种方法仅在向下一级更改。因此,对于嵌套对象或更具体而言,您可以执行以下操作:

  addItem = id => {
    const enteredTask = prompt("Please enter a task");
    const newData = [...this.state.data];  // changed array's reference here

    // changed reference of nested object
    newData[id].info = [...d.info, enteredTask]; 
    this.setState({ data: newData });
 };

希望这会有所帮助:)

答案 1 :(得分:0)

您需要先检查this.state.data,然后才能在map方法中使用render来停止出现的错误:

render() {
  return (
    <div>
      <h3 className="header">Dashboard</h3>
      <div className="card-parent">
        {this.state.data && this.state.data.map(d => {
          return <Card key={d.id} info={d} addItem={this.addItem} />;
        })}
      </div>
    </div>
  );
}

...以及render组件的Card方法中的相同内容:

{this.props.info.info && this.props.info.info.map(i => {
  return <p className="card-info">{i}</p>;
})}

然后,您可以在更新数据之后而不是在addItem的每次迭代中更新setState方法以调用map

addItem = id => {
  const enteredTask = prompt("Please enter a task");

  const newData = this.state.data.map(d => {
    if (d.id == id) {
      d.info = [...d.info, enteredTask];
    }
    return d;
  });

  this.setState({ data: newData });
};

我希望这会有所帮助。

答案 2 :(得分:0)

这是根据尼克的建议而稍作更改的答案,谢谢大家的帮助

  addItem = id => {
    const enteredTask = prompt("Please enter a task");
    let new_arr = [...this.state.data];

    this.state.data.map(d => {
      if (d.id === id) {
        new_arr[id].info = [...d.info, enteredTask];
        this.setState({
          data: new_arr
        });
      }
    });
  };