React 组件状态
状态(state)是组件自己保存、会随时间变化的数据,比如计数器、输入框内容、开关状态。界面要"动"起来就必须让组件拥有状态,这也是 React 数据驱动视图的核心机制。
什么是 state
state 与 props 的区别在于:props 由父组件传入、组件内部只读;state 由组件自己管理,能通过专门的方法更新。state 一旦变化,React 会自动重新渲染相关界面。
函数组件:useState
useState 是 React 提供的 Hook,返回"当前值"和"更新函数"两个元素,可解构出来使用:
import { useState } from 'react'
function Counter() {
const [count, setCount] = useState(0)
return (
<div>
<p>点击了 {count} 次</p>
<button onClick={() => setCount(count + 1)}>加一</button>
</div>
)
}
count 初始值为 0,每次点击按钮 setCount 写入新值,界面自动刷新。
类组件:this.state 与 setState
类组件用 this.state 保存状态,且必须通过 this.setState() 更新,直接给 this.state 赋值不会生效:
import { Component } from 'react'
class Counter extends Component {
constructor(props) {
super(props)
this.state = { count: 0 }
}
handleClick = () => {
this.setState({ count: this.state.count + 1 })
}
render() {
return (
<div>
<p>点击了 {this.state.count} 次</p>
<button onClick={this.handleClick}>加一</button>
</div>
)
}
}
setState 会自动合并对象字段,并触发一次重新渲染。
更新是"替换式"的:先复制再改
对象、数组这类引用类型状态,直接修改原数据不会触发渲染,必须创建新副本再交给 setState / setter:
const [user, setUser] = useState({ name: '小明', age: 18 })
// 错误:原地修改属性,界面不会更新
user.age = 19
// 正确:展开旧对象生成新对象
setUser({ ...user, age: 19 })
函数式更新:新值依赖旧值
同一事件里连续多次 setState 会被合并成一次渲染;当新值要基于旧值计算时,传入函数形式最稳妥:
setCount(c => c + 1)
setCount(c => c + 1)
// 连续调用两次,最终 count 比原来大 2(参数 c 始终是最新值)
小结:state 是组件的"记忆"。函数组件用 useState、类组件用 this.state/setState;修改对象状态务必先复制出新副本,依赖旧值时改用函数式更新,界面就会随状态自动刷新。