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

时间:2019-10-12 09:39:00

标签: reactjs react-state-management react-state

我正在React中构建一个简单的TODO应用。我在状态中有一个todos数组,并且每个todo都有一个标志completed。单击某个项目后,我想切换该completed的{​​{1}}标志。到目前为止,这是我所做的:

Todos.js

todo

Todo.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>
    );
  }
}

Todos.js 中,调用了函数class Todo extends React.Component { render() { return ( <div onClick={() => this.props.todoClicked(this.props.id)}> {this.props.todo.title} </div> ); } } ,它会打印出正确的ID,但是状态没有其他变化(我使用React开发工具和console.log)。单击的项目不会更改其onTodoClicked标志。我在做什么错了?

4 个答案:

答案 0 :(得分:2)

最好依靠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>

答案 1 :(得分:1)

那是它的外观:

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>

答案 2 :(得分:0)

您必须在 onTodoClicked 函数中进行更改。它将起作用。

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);
      }

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

答案 3 :(得分:0)

这是您在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 };
     });
   });
  }

我希望这会对您有所帮助。