繁体   English   中英

反应中 setState 代码的奇怪双重执行

[英]Strange double execution of setState code in react

我有一个组件,它显示一些待办事项列表,例如

const todosData = [
  {
      id: 1,
      text: "Take out the trash",
      completed: true
  },
  {
      id: 2,
      text: "Grocery shopping",
      completed: false
  },
];

我有一个触发一个简单更改的按钮:它将字符“1”添加到第一个元素的文本属性。 我的处理程序看起来像这样

    handleChange() {
      this.setState(prevState => {
          const updatedTodos = prevState.todos.map(todo => {
              if (todo.id === 1) {
                todo.text += 1
                console.log(todo.text)
                // here i get Take out the trash1, Take...trash111, Take...trash11111 and etc
              }  
              return todo
          })
          return {
              todos: updatedTodos
          }
      })
  }

和简单的渲染

render() { 
        return (
            <ul className="todo-list">
              {this.state.todos.map(item => <li>{item.text}</li>)}
              <button onClick={this.handleChange}>change me</button>  
            </ul>
        )    
    }

所以我希望在点击后看到控制台中的“取出垃圾箱1”和页面上的相同文本。 相反,我在控制台中按预期看到“取出垃圾 1”,但在页面上我看到“取出垃圾 11”,然后“取出垃圾 1111”,因为此代码工作双倍,但是为什么在控制台中我看到第一次工作的唯一结果:“取出垃圾1”,“取出垃圾111”?

是的,我知道改变这样的项目不是正确的方法,我应该这样做

todo = {...todo, text: todo.text += 1} 

如果我这样写 - 一切正常,并且这段代码还有其他不足之处,实际上这段代码不是我的,但我只是想知道这种魔法是如何发生的:

  1. 为什么它工作两次
  2. 为什么我在控制台中只看到第一个输出

沙盒示例https://codesandbox.io/s/objective-margulis-0phvx?file=/src/App.js

这是个有趣的问题。 您可以尝试使用字母(或任何字符串),同样的事情也会发生。 你也可以在开头附加一个字符串,同样的事情也会发生。

例如

todo.text = 'boo' + todo.text + 'doo'

我完全没有受过教育的猜测是,在 React 内部的某个地方,它会进行某种字符串比较并找出差异所在; 并且可能您的代码修改了原始对象中的字符串,并且在应用它时,它会将其应用于已修改的字符串。

但是...如果我这样做:

const t = Date.now();
while(Date.now() < t + 1);
todo.text = 'a_' + todo.text + '_b_' + t;

字符串的 t 部分不会保持不变。

有趣的是,如果你这样做:

todo.text = 'a_' + todo.text + alert(todo.text);

发出两次警报(尽管正如您所提到的,它只发出一次 console.logs)。

所以看起来这段代码由于某种原因确实运行了两次。 我不知道为什么只有一个 console.log 消息。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM