簡體   English   中英

React 函數式組件,setState 和不變性

[英]React functional components, setState and immutability

感覺有點笨,我使用 React 已經 2 年了,一直認為你必須使用setState和 object 的新副本,以避免改變 state。 但是,此示例對 state 進行了變異,並將setState與相同的 object 引用一起使用,沒有任何問題。

為什么這行得通?

工作代碼筆

const { useState } = React;

const Counter = () => {
  const [countObject, setCountObject] = useState({count: 0});

  const onClick = () => {
    countObject.count = countObject.count + 1;
    setCountObject(countObject); // mutated object, same reference
    
  }
  
  return (
    <div>
      <p>You clicked {countObject.count} times</p>
      <button onClick={onClick}>
        Click me
      </button>
    </div>
  )
}

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

您的 codepen 使用的是 React 16.7 的 alpha 版本。 Hooks 是在 16.8 中發布的,所以要可靠地使用 hooks,你應該使用 16.8 或更高版本(在 React 的非 alpha 版本中):

在此處輸入圖像描述

您可以通過單擊 JavaScript 窗格上代碼筆中的齒輪圖標來更新上述兩個鏈接的版本號。

請注意,以下代碼段使用16.7.0-alpha.2並遇到您遇到的相同問題:

 const { useState } = React; const Counter = () => { const [countObject, setCountObject] = useState({count: 0}); const onClick = () => { countObject.count = countObject.count + 1; setCountObject(countObject); } return ( <div> <p>You clicked {countObject.count} times</p> <button onClick={onClick}> Click me </button> </div> ) } ReactDOM.render(<Counter />, document.getElementById('app'))
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.7.0-alpha.2/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.7.0-alpha.2/umd/react-dom.production.min.js"></script> <div id="app"></div>

但是,將您的版本更改為16.8或更高版本可以解決此問題(在撰寫本文時,我們已更新至 v17.0.2):

 const { useState } = React; const Counter = () => { const [countObject, setCountObject] = useState({count: 0}); const onClick = () => { countObject.count = countObject.count + 1; setCountObject(countObject); } return ( <div> <p>You clicked {countObject.count} times</p> <button onClick={onClick}> Click me </button> </div> ) } ReactDOM.render(<Counter />, document.getElementById('app'))
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script> <div id="app"></div>

不變性當然很重要,你的代碼可以工作,只是因為修改原來的 object 不會影響功能。 通過共享初始值更改代碼,然后單擊任意按鈕,您會發現有問題。

const { useState } = React;

const Counter = () => {
  const value = { count: 0 }
  const [countObject, setCountObject] = useState(value);
  const [countObject2, setCountObject2] = useState(value);

  const onClick = () => {
    countObject.count = countObject.count + 1;
    setCountObject(countObject);
  }
  
  const onClick2 = () => {
    countObject2.count = countObject2.count + 1;
    setCountObject(countObject2);
  }
  
  return (
    <div>
      <p>You clicked {countObject.count} times</p>
      <button onClick={onClick}>
        Click me
      </button>

      <p>You2 clicked {countObject2.count} times</p>
      <button onClick={onClick2}>
        Click me2
      </button>
    </div>
  )
}

ReactDOM.render(<div><Counter /></div>, document.getElementById('app'))

正如 Nick Parsons 所提到的,這是 Code Pen 中使用的 React 版本的問題。 這是更新了 React 版本的同一支筆,它不起作用(因為它不應該):

https://codepen.io/gfels/pen/QWqZxLP?editors=1111

重新發布 onClick function,因為 StackOverflow 需要帶有代碼筆的代碼

  const onClick = () => {
    countObject.count = countObject.count + 1;
    setCountObject(countObject); // mutated object, same reference
  }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM