簡體   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