无法在使用 React 的 ToDo 应用程序中使用 ES6 映射状态?

Cannot map through state using ES6 in a ToDo App using React?

我正在开发一个简单的 ToDo 应用程序,目前我一直在更新我的 App.js 组件的状态。

这是我的 App.js:

import React, { Component } from "react";
import TodoItem from "./ToDoItem";
import todosData from "./ToDoData";

class App extends Component {
  constructor() {
    super();
    this.state = {
      loadedData: todosData,
    };
  }

  newChange = (id) => {
    const update = this.state.loadedData.map((todo) => {
      if (todo.id === id) {
        todo.completed = !todo.completed;
      }
      return todo;
    });
    // this is where my update variable will not update?
    console.log(update);
    this.setState({ loadedData: update });
  };

  render() {
    const todoComponent = this.state.loadedData.map((item) => (
      <TodoItem
        key={item.id}
        text={item.text}
        completed={item.completed}
        newChange={this.newChange}
      />
    ));

    return <div className="todo-list">{todoComponent}</div>;
  }
}

export default App;

这是我的 TodoItem Componenet(我猜一旦这个状态被正确传递就会正常工作):

import React from "react";

class TodoItem extends React.Component {
  render() {
    return (
      <div className="todo-item">
        <input
          type="checkbox"
          checked={this.props.completed}
          onChange={() => this.props.newChange(this.props.id)}
        />
        <p>{this.props.text}</p>
      </div>
    );
  }
}

export default TodoItem;

最后,我的数据只是一个由对象组成的数组:

    const todosData = [
  {
      id: 1,
      text: "Take out the trash",
      completed: true
  },
  {
      id: 2,
      text: "Grocery shopping",
      completed: false
  },
  {
      id: 3,
      text: "Clean gecko tank",
      completed: false
  },
  {
      id: 4,
      text: "Mow lawn",
      completed: true
  },
  {
      id: 5,
      text: "Catch up on Arrested Development",
      completed: false
  }
]

export default todosData

我最大的问题是为什么我的 newChange() 方法中的 update 变量在我映射时没有更新?

当我 console.log 它显示完全相同的数据时,我想要的 属性 没有得到更新?

loadedData 仍然与 update 完全相同。

当您执行以下操作时,您不小心改变了 newChange 处理程序中的状态:

todo.completed = !todo.completed;

相反,创建一个全新的 state 对象切片:

newChange = (id) => {
  this.setState({
    loadedData: this.state.loadedData.map((todo) => ({
      ...todo,
      completed: todo.id === id ? !todo.completed : todo.completed,
    })),
  });
};

或者,如果您不能使用扩展运算符 (...),请尝试以下操作:

newChange = (id) => {
  this.setState({
    loadedData: this.state.loadedData.map((todo) =>
      Object.assign({}, todo, {
        completed: todo.id === id ? !todo.completed : todo.completed,
      })
    ),
  });
};

您可以在“The Power Of Not Mutating Data”下的官方 React 文档中阅读更多信息

您在 App.js

中创建 ToDoItems 时只是缺少一个道具 (id)

您尝试在 ToDoItem 中访问它,但您从未设置它...

所以你在 App 中的渲染函数应该是这样的:

render() {
    const todoComponent = this.state.loadedData.map((item) => (
      <TodoItem
        key={item.id}
        id={item.id}
        text={item.text}
        completed={item.completed}
        newChange={this.newChange}
      />
    ));

    return <div className="todo-list">{todoComponent}</div>;
  }

丹尼,你把 console.log(update) 放在那里是正确的。这样你发现函数实际上并没有更新map函数中已有的状态。

要找出原因,您需要检查 map 函数内部发生了什么,第一步是测试您在那里使用的所有内容。在这种情况下,您使用的是 this.props.id,您可以通过输入 console.log 来检查它的值:

  newChange = id => {
    console.log("id:", id); // NEW
    const update = this.state.loadedData.map(todo => {
      if (todo.id === id) {
        todo.completed = !todo.completed;
      }
      return todo;
    });
    // this is where my update variable will not update?
    console.log(update);
    this.setState({ loadedData: update });
  };

好吧,在这种情况下,当您尝试单击待办事项时,它会打印 id: undefined,因为您实际上并没有将其作为道具传递。 map 函数循环遍历待办事项,但从未找到任何满足 if (todo.id === id) 的待办事项(因为它在您的情况下转换为 if (todo.id === undefined)

修复很简单,只需将 id 作为 prop 传递给 todoComponent

  const todoComponent = this.state.loadedData.map(item => (
      <TodoItem
        id={item.id} // NEW
        key={item.id}
        text={item.text}
        completed={item.completed}
        newChange={this.newChange}
      />
    ));