useState、useReducer、useContext
本文由 AI 协助更新
本文介绍三个与状态相关的 Hook:useState(局部状态)、useContext(跨层级读取数据)、useReducer(复杂状态逻辑)。
React Hook 简介
Hook 是让我们在函数组件里「勾入」React 状态与生命周期的函数。
组件负责渲染,React Hook 负责行为和数据。
下面这段代码里,每次调用 setCurrentTodo 或 setInputText 都会触发一次重新渲染(即 App 再次执行并返回新元素)。同一轮渲染里,useState 会返回当前的 state 和稳定的 setter 引用——setter 可以安全地传给子组件或放进依赖数组。
function App() {
const [currentTodo, setCurrentTodo] = useState('')
const [inputText, setInputText] = useState('')
return (
<View style={styles.container}>
<TodoItem title={currentTodo || '请输入待办事项'} />
<TextInput
value={inputText}
onChangeText={setInputText}
placeholder="输入待办事项"
style={styles.input}
/>
<Button title="添加" onPress={() => setCurrentTodo(inputText)} />
</View>
)
}
原理细节可看 官方文档。下面分别说三个 Hook。
useState
用于在组件内维护一块局部状态。
const [state, setState] = useState(initialState)
- 返回当前
state和更新函数setState。 - 首次渲染时,
state等于initialState;之后渲染中,initialState会被忽略。
初始值
若初始状态依赖较重计算,可传函数,只在首次渲染时执行一次:
const [todos, setTodos] = useState(() => loadTodosFromStorage())
更新 state
调用 setState(newState) 会把一次更新加入队列,React 在后续渲染中把 useState 返回的 state 更新为最新值。
若新状态要基于上一次 state 计算,应传函数,避免闭包拿到旧值:
setTodos((prevTodos) => [...prevTodos, newTodo])
注意
- 能从其它 state 推导出的值,不要再用
useState存一份,直接计算即可。
useContext
用于在组件树中跨层级读取同一份数据,无需层层传 props。
const value = useContext(SomeContext)
需要先用 createContext 创建 Context,再在祖先节点用 Context.Provider 提供 value,子组件(任意深度)用 useContext 消费。
示例:把「筛选状态」通过 Context 传给深层子组件,子组件不必通过 props 一层层接收。
import React, { createContext, useContext, useState } from 'react'
const TodoFilterContext = createContext<string>('all')
function TodoItem({ title }: { title: string }) {
const filter = useContext(TodoFilterContext)
return <Text>【{filter}】{title}</Text>
}
function TodoList() {
const todos = ['买菜', '写代码', '运动']
return (
<View>
{todos.map((todo, index) => (
<TodoItem key={index} title={todo} />
))}
</View>
)
}
function App() {
const [filter, setFilter] = useState('all')
return (
<TodoFilterContext.Provider value={filter}>
<View style={styles.container}>
<Button
title="切换筛选"
onPress={() => setFilter(filter === 'all' ? 'active' : 'all')}
/>
<TodoList />
</View>
</TodoFilterContext.Provider>
)
}
更多在 React Native 里用 Context 做跨层级通讯的实践,可参考 React Native 可复用 UI 小技巧:分离布局组件和状态组件。
useReducer
我们很少使用 useReducer;若不确定是否需要,可以先用 useState。
const [state, dispatch] = useReducer(reducer, initialArg, init)
适合:状态结构复杂、有多子字段,或下一状态强依赖上一状态、更新逻辑较多时。可减少「多个 useState + 多处 setState」带来的重复逻辑。用法与示例见 官方文档 useReducer。