javascript - React 函数式组件,setState 和不变性

标签 javascript reactjs react-hooks

感觉有点笨,我用 React 已经 2 年了,一直认为你必须使用 setState使用对象的新副本以避免改变状态。然而,这个例子改变了状态并使用了 setState使用相同的对象引用没有任何问题。
为什么这行得通?
Working Code Pen

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 版本中):
enter image description here
您可以通过单击 JavaScript Pane 上代码笔中的齿轮图标来更新上述两个链接的版本号。
请注意,以下代码段使用 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>

关于javascript - React 函数式组件,setState 和不变性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70664935/

相关文章:

javascript - ES6 覆盖父方法

javascript - ag-grid:根据rowNode内容在fullRow编辑和单个单元格编辑之间切换

reactjs - 访问 Redux reducer 中状态的其他部分

javascript - 如何在同一个 <div> 容器中加载远程 html 页面链接?

javascript - 不显示特定通知 React Native

javascript - 如何在 JavaScript 中将 Unix 时间戳转换为 ISO 8601?

reactjs - 为什么我能够以一种方式有条件地调用 Hook ,而不能以另一种方式有条件地调用 Hook ?

javascript - 在我的服务器上安装/设置 Socket.IO

reactjs - 使用 useReducer 手动获取数据

javascript - 如何在 React useState 中存储和更新多个值?