Skip to content

useState

基本使用

介绍

useState 是一个 hooks 函数,它允许我们向组件添加一个状态变量,从而控制影响组件的渲染结果。

提示

可以类比于 vue2 中的 data,或者 vue3 中的 ref、reactive。

示例

tsx
import { useState } from 'react'

function State() {
  const [count, setCount] = useState(0)
  const handleClick = () => {
    setCount(count + 1)
  }

  const [obj, setObj] = useState({
    name: '张三',
    age: 18,
  })
  const handleClick2 = () => {
    setObj({
      ...obj,
      name: '李四',
    })
  }

  const [arr, setArr] = useState([1, 2, 3])
  const handleClick3 = () => {
    setArr([4, 5, 6])
  }

  return (
    <>
      {/* 基本状态 */}
      <h2>{count}</h2>
      <button type="button" onClick={handleClick}>
        count++
      </button>

      <hr />
      {/* 对象状态 */}
      <h2>{JSON.stringify(obj)}</h2>
      <button type="button" onClick={handleClick2}>
        更改 obj
      </button>

      <hr />
      {/* 数组状态 */}
      <h2>{JSON.stringify(arr)}</h2>
      <button type="button" onClick={handleClick3}>
        添加 arr
      </button>
    </>
  )
}

export default State

计算属性

jsx
import { useState } from 'react'

function App() {
  const [count] = useState(10)
  const doubleCount = count * 2

  return <div>{doubleCount}</div>
}

export default App

setState 的更新是异步的吗?

是“延迟处理”,所以看起像“异步”处理的错觉。

  1. 同步提交,延迟执行setState 函数本身是同步的,但它触发的状态更新和组件重新渲染,会被 React 延迟处理 并进行 批量合并
  2. 性能优化:通过将多次状态更新合并成单次渲染,避免不必要的计算和 DOM 操作,最大化应用性能。
  3. 状态一致性:保证在一次事件处理流程中,所有状态变更能够同时生效,防止用户看见不完整的中间 UI 状态,提升应用健壮性。

useState 的两种更新方式

js
const [count, setCount] = useState(0)

const handleClick = () => {
  setCount(count + 1)
}
js
const [count, setCount] = useState(0)

const handleClick = () => {
  setCount((prevCount) => prevCount + 1)
}

示例:State 更新不符合预期

在一次点击中,连续调用了三次 setCount,期望 count 增加 3:

jsx
import { useState } from 'react'

function Counter() {
  const [count, setCount] = useState(0)

  const handleClick = () => {
    setCount(count + 1)
    setCount(count + 1)
    setCount(count + 1)
  }

  return (
    <div>
      <p>{count}</p>
      <button onClick={handleClick}>Increment by 3</button>
    </div>
  )
}

export default Counter

结果是:count 只增加了 1。

提示

  1. 闭包陷阱:handleClick 函数作用域内的 count 值,永远是当前渲染时的“快照”(0)。
  2. 异步与批处理:React 会将短时间的多次 setCount 调用合并处理,以此来优化性能。

解决方案就是,使用“函数式更新”,通过函数获取最新的 state:

jsx
import { useState } from 'react'

function Counter() {
  const [count, setCount] = useState(0)

  const handleClick = () => {
    setCount((prevCount) => prevCount + 1)
    setCount((prevCount) => prevCount + 1)
    setCount((prevCount) => prevCount + 1)
  }

  return (
    <div>
      <p>{count}</p>
      <button onClick={handleClick}>Increment by 3</button>
    </div>
  )
}

export default Counter

结果是:count 增加了 3。

如果新状态依赖于旧状态,直接使用函数是更新!

基于 MIT 许可发布