如何在不修改React中的其他项的情况下将项的值更改为数组

时间:2016-10-23 17:31:14

标签: javascript reactjs

我有一个简单的todolist结构到组件的状态。这是一个包含两个名为“content”的字段和一个名为“done”的字段的数组。我通过从父对象传递到TodoItem子项的简单onClick()函数来捕获行项目的点击(如React教程建议):

  render() {
   const tthis = this;

   var myList = tthis.state.todos.map(function(todo,index){

      var myOnCLick = function(){
        var newTodo = {content: todo.content, done: !todo.done};
        tthis.state.todos[index] = newTodo;
        tthis.setState({});

      }
      return <Todo key={index} todo={todo} onClick={myOnCLick}/>
   })

   return (
     <ul className="list">
       { myList }
     </ul>
   )
 }

这段代码没有问题,但我不太喜欢。 我会找到一些很好的解决方案来改变数组中单个项的值。我在React DOC的Immutability helper中找到了:

  

{$ set:any}完全替换目标。

在这个论坛中,我看到了一个很好的答案:

this.setState({
  todos: update(this.state.todos, {1: {done: {$set: true}}})

但我不能在我的情况下使用1。我有索引,它给了我todos列表中点击待办事项的索引。

1 个答案:

答案 0 :(得分:1)

您可以按以下方式翻转数组中列出的单个待办事项对象的done属性的值:

flipDone(id) {
  let index = Number(id);

  this.setState({
    todos: [
      ...this.state.todos.slice(0, index),
      Object.assign({}, this.state.todos[index], {done: !this.state.todos[index].done}),
      ...this.state.todos.slice(index + 1)
    ]
  });
}

以下是演示:http://codepen.io/PiotrBerebecki/pen/jrdwzB

完整代码:

class TodoList extends React.Component {
  constructor() {
    super();
    this.flipDone = this.flipDone.bind(this);
    this.state = {
      todos: [
        {content: 'Go shopping', done: false},
        {content: 'Walk the dog', done: false},
        {content: 'Wash the dishes', done: false},
        {content: 'Learn React', done: false}
      ]
    };
  }

  flipDone(id) {
    let index = Number(id);

    this.setState({
      todos: [
        ...this.state.todos.slice(0, index),
        Object.assign({}, this.state.todos[index], {done: !this.state.todos[index].done}),
        ...this.state.todos.slice(index + 1)
      ]
    });
  }

  render() {
    const myList = this.state.todos.map((todo, index) => {
      return (
        <Todo key={index} 
              clickHandler={this.flipDone} 
              content={todo.content}
              done={todo.done}
              id={index}
        />
      );
    })

    return (
      <ul className="list">
        {myList}
      </ul>
    );
  }
}


class Todo extends React.Component {
  constructor() {
    super();
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(event) {
    this.props.clickHandler(event.target.id);
  }

  render() {
    return (
      <li>
        <button onClick={this.handleClick}
                id={this.props.id}>
          Click me
        </button> --- 
        {String(this.props.done)} --- 
        {this.props.content}      
      </li>
    );
  }
}


ReactDOM.render(
  <TodoList />,
  document.getElementById('app')
);