更新状态数组对象中的字段

Update field in state array object

我正在用 React 构建一个简单的 TODO 应用程序。我在状态中有一个todos数组,每个todo都有一个标志completed。单击某个项目时,我想切换 todocompleted 标志。这是我到目前为止所做的:

Todos.js

class Todos extends React.Component {
  constructor() {
    super();
    this.state = {
      todos: [
          { id:0, title:"Title 0", completed:false },
          { id:1, title:"Title 1", completed:true }
         ]
    };
    this.onTodoClicked = this.onTodoClicked.bind(this);
  }

  onTodoClicked(id) {
    console.log(id + " clicked");
    this.setState(prevState => {
      todos: prevState.todos.map((item, index) => {
        return index !== id ? item : { ...item, completed: !item.completed };
      });
    });
  }

  render() {
    return (
      <div>
        {this.state.todos.map((todoItem, key) => (
          <Todo id={key} key={key} todo={todoItem}
            todoClicked={this.onTodoClicked} />
        ))}
      </div>
    );
  }
}

Todo.js 只是一个简单的组件(是的,它也可以发挥作用)

class Todo extends React.Component {
  render() {
    return (
      <div onClick={() => this.props.todoClicked(this.props.id)}>
        {this.props.todo.title}
      </div>
    );
  }
}

Todos.js中调用函数onTodoClicked并打印出正确的id,但状态没有其他变化(我检查了点击的使用 React 开发工具和 console.log 的对象)。单击的项目不会更改其 completed 标志。我做错了什么?

最好依靠 id,而不是 index:

return item.id !== id ? item : { ...item, completed: !item.completed };

另外,对于 Todo id,您应该传递 id,而不是键 (id={key})(或者只传递整个 todoItem):

id={todoItem.id}

对于 Todo 键也传递 id,因为传递相同的 key 索引,您的 Todo 项目可能不会重新呈现。

最后,您在 prevState => ({

之后缺少括号

class Todo extends React.Component {
  render() {
    return (
      <div onClick={() => this.props.todoClicked(this.props.todo.id)}>
        {this.props.todo.title} - {this.props.todo.completed.toString()}
      </div>
    );
  }
}

class Todos extends React.Component {
  constructor() {
    super();
    this.state = {
      todos: [
          { id:0, title:"Title 0", completed:false },
          { id:1, title:"Title 1", completed:true }
         ]
    };
    this.onTodoClicked = this.onTodoClicked.bind(this);
  }

  onTodoClicked(id) {
    console.log(id);
    this.setState(prevState => ({
      todos: prevState.todos.map((item, index) => {
        return item.id !== id ? item : { ...item, completed: !item.completed };
      })
    }));
  }

  render() {
    return (
      <div>
        {this.state.todos.map((todoItem, key) => (
          <Todo key={todoItem.id} todo={todoItem}
            todoClicked={this.onTodoClicked} />
        ))}
      </div>
    );
  }
}

ReactDOM.render(<Todos />, document.querySelector("#container"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="container"></div>

您必须更改 onTodoClicked Function.it 才会起作用。

onTodoClicked(id) {
        console.log(id + " clicked");
        this.state.todos[id].completed = !this.state.todos[id].completed;
        this.setState({ todos: this.state.todos });
        console.log("state,", this.state.todos);
      }

这是link:https://stackblitz.com/edit/react-yxxksp?file=index.js

应该是这样的:

class Todos extends React.Component {
  constructor() {
    super();
    this.state = {
      todos: [
          { id:0, title:"Title 0", completed:false },
          { id:1, title:"Title 1", completed:true }
         ]
    };
    this.onTodoClicked = this.onTodoClicked.bind(this);
  }

  onTodoClicked(id) {
    console.log(id + " clicked");
    this.setState(prevState => ({
      todos: prevState.todos.map((item, index) => {
        return item.id !== id ? item : { ...item, completed: !item.completed };
      })
    }));
  }

  render() {
    return (
      <div>
        {this.state.todos.map((todoItem, key) => (
          <Todo key={key} todo={todoItem}
            todoClicked={this.onTodoClicked} />
        ))}
      </div>
    );
  }
}

class Todo extends React.Component {
  render() {
    return (
      <div onClick={() => this.props.todoClicked(this.props.todo.id)}>
        {this.props.todo.title} {this.props.todo.completed && "completed"}
      </div>
    );
  }
}

ReactDOM.render(<Todos/>, document.getElementById("root"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

这是您在 Todo.js

中可以做的
class Todo extends React.Component {
  render() {
    return (
     <div onClick={() => this.props.todoClicked(this.props.todo.id)}>
       {this.props.todo.title}
     </div>
  );
 }
}

在 onTodoClicked 函数中,你可以做这样的事情。

onTodoClicked(id) {
    this.setState(prevState => {
      todos: prevState.todos.map((item) => {
       return item.id !== id ? item : { ...item, completed: !item.completed };
     });
   });
  }

希望对您有所帮助。