
先看一个不工作的写法
function Counter() { let count = 0 return <button onClick={() => count++}>点了 {count} 次</button>}点多少下都显示「点了 0 次」。count 是渲染时的局部变量,函数每渲染一次就重建一遍,改它不会让 React 知道该重渲染。
useState 补上的就是这块记忆
import { useState } from 'react'
function Counter() { const [count, setCount] = useState(0) return <button onClick={() => setCount(count + 1)}>点了 {count} 次</button>}useState(0) 返回一个两元数组:当前值,与更新函数。命名习惯是 [x, setX]。
关键在 setCount 到底做了什么。它不改 count,而是请 React 用新值再渲染一次。本次渲染里的 count 是一个不会再变的快照,所以下面这段打印的是旧值:
const handleClick = () => { setCount(count + 1) console.log(count) // 旧值}官方把这条讲成「状态是一次渲染的快照」(State as a Snapshot)。要拿最新值,用更新函数形式,或者干脆在渲染时算。
依赖旧值时用更新函数
setCount(count + 1) // 用的是本次渲染的快照setCount(prev => prev + 1) // 用的是最新的待处理值连续调用两次时差别就出来了。同一个事件里写两次 setCount(count + 1),两次读到的 count 是同一个快照,结果只加 1;写两次 setCount(prev => prev + 1) 则加 2。官方在 Queueing a Series of State Updates 里把这件事讲成排队:更新函数依次作用在前一个结果上。
对象与数组要返回新引用
useState 与类组件的 this.setState 不同,它不做属性合并,也不检查你有没有改原对象。直接改字段再 set 回去,React 拿到的是同一个引用,界面不动:
// 不会重渲染function handleClick() { user.name = '新名字' setUser(user)}
// 返回新对象function handleClick() { setUser(prev => ({ ...prev, name: '新名字' }))}数组同理,用 [...list, item]、list.filter(...)、list.map(...) 这类返回新数组的写法,不要 push。完整清单在官方 Updating Objects in State 与 Updating Arrays in State。
初始值只在首次渲染用到
useState(initial) 里的初始值只在组件第一次挂载时参与,之后重渲染会忽略它。
如果初始值要算出来(读 localStorage、遍历大数组),传函数做惰性初始化:
const [rows, setRows] = useState(() => buildRows(props.data))直接写 useState(buildRows(props.data)) 的话,每次渲染都会算一遍再丢掉。
只能在顶层调用
Hooks 的调用顺序就是 React 对号入座的依据,所以 useState 只能写在组件或自定义 Hook 的顶层:
// 不行function Bad({ show }) { if (show) { const [count, setCount] = useState(0) } return null}条件分支要挪到 useState 之后,改为控制渲染内容。规则全文见 Rules of Hooks。
什么数据不该放状态
能由 props 或已有状态算出来的,就别再存一份。冗余状态最难保持一致:
// 冗余:fullName 完全可以算出来const [firstName, setFirstName] = useState('')const [lastName, setLastName] = useState('')const [fullName, setFullName] = useState('')渲染时直接拼 firstName 与 lastName 就行。这一类的判断方法见官方 Choosing the State Structure。
分享文章
生成精美分享图或复制链接,与更多人分享本文。
继续阅读
换条路线
从其他文章中稳定抽取
最后更新于 ,距今已过 190 天
部分内容可能已过时