useReducer() 的用法注意事项
1、 概述:
useReducer()
常用于管理复杂 的状态更新逻辑,特别是在状态更新依赖于多个条件
或动作时
,useReducer
提供了一种更加结构化和可维护的方式来处理状态。可以将更新函数写在组件外面
它与 useState() 相似,useState()
用于处理相对简单的状态更新逻辑
;
2、什么是useReducer():
它是React
提供的一个 HOOK
,用于处理复杂的状态管理,特别是更新逻辑比较复杂,或者有多个状态相互依赖的逻辑业务中;
useReducer(reducer, initialArg, init?)
接收三个参数
第一个参数 :reducer 用于更新 state
的纯函数
,function(state, action) {};函数接收两个参数 state、action
;
其中 state 是只能读取
的状态值,不能
在纯函数里面进行直接修改
;
其中 action 是用户进行操作的函数,
第二个参数 :initialArg
:用于初始化 state 的任意值
,在没有第三个参数时候,直接取当前值为默认值,
第三个参数 :init:为可选参数,用于处理state 的默认值函数
;
3、基本写法:
javascript
const [count, dispatch] = useReducer(reducer, initState, initFunc)
useReducer()
: 利用数组解构,得到两个参数,
count :当前state的初始值,
dispatch :用于触发count 更新的分发函数;
通常为一个包含type属性的对象
;如
javascript
const [count, dispatch] = useReducer(reducer, {count: 1}, initFunc)
function handleDispatch() {
dispatch({type: 'ADD'})
}
4、 具体使用例子
国庆出游计划 增删改成游玩项目
4.1 、声明reducer逻辑处理函数
注意:跟useState
一样,修改数组、对象时候,需要修改其指针
,否则React视为当前值没有发生改变
javascript
// taskReducer 文件
export default function taskReducer(tasks, action) {
switch(action.type) {
case 'added':{
return [
...tasks,
{
id: action.id,
text: action.text,
done: false,
}
]
}
case 'changed' : {
return tasks.map(itm => {
if (itm.id === action.task.id) {
return action.task
} else {
return itm
}
}
)
}
case 'deleted' : {
return tasks.filter(itm => itm.id!== action.id)
}
}
}
a 、在 reducer
函数中 通常我们会使用 switch
进行处理type类型条件
,当然了你也可以使用if() {}语句,
b 、taskReducer
函数中设计了新增、删除、修改三个类型;
c 、根据传入的 action 中type
类型来处理更新 tasks 的状态;
4.2、在组件中使用 useReducer
声明一个任务组件TaskApp
javascript
import { useState, useReducer } from 'react'
import taskReducer from './taskReducer'
// ...
export default function TaskApp() {
const [tasks, dispatch] = useReducer(taskReducer, initialTasks)
//...
}
// 声明初始值
const initialTasks = [
{id: 0, text: '参观卡夫卡博物馆', done: true},
{id: 1, text: '看木偶戏', done: false},
{id: 2, text: '打卡列侬墙', done: false}
];
此时我们得到一个tasks 初始值
,以及一个dispatch
分发函数
通过调用 dispatch 来触发 taskReducer 函数中对应条件执行
比如要删除一个旅游项目
javascript
// ...
function handleDeleteTask(taskId) {
dispatch({
type: 'deleted', // 直接传入 type类型为 deleted,
id: taskId,
})
}
// ...
4.3、完整代码
javascript
// TaskApp 组件文件
import { useReducer } from 'react'
// 新增旅游项目组件
import AddTask from './taskAdd'
// 旅游项目列表组件
import TaskList from './taskList'
export default function TaskApp() {
const [tasks, dispatch] = useReducer(taskReducer, initialTasks)
// 使用dispatch 触发新增操作
function handleAddTask(text) {
console.log('==handleAddTask=', nextId)
dispatch({
type:'added',
id: nextId++,
text: text,
})
}
function handleChangeTask(task) {
console.log('=handleChangeTask==', task)
dispatch({
type:'changed',
task: task
})
}
// 删除操作
function handleDeleteTask(taskId) {
dispatch({
type: 'deleted',
id: taskId,
})
}
return (
<>
<h1 style={{color: 'red'}}>国庆旅游计划</h1>
<AddTask onAddTask={handleAddTask}></AddTask>
<TaskList
tasks={tasks}
onChangeTask={handleChangeTask}
onDeleteTask={handleDeleteTask}
></TaskList>
</>
)
}
let nextId = 3;
在AddTask
组件中 ,新增操时候 重置了input
输入框的值,
同时给父组件传递了onAddTask
函数,触发父组件中的 handleAddTask
函数执行;
javascript
// AddTask 文件
import { useState } from 'react'
export default function AddTask ({onAddTask}) {
const [text, setText] = useState('')
console.log('===useState==', useState())
// 通过useState 的setText 触发视图更新
function handleChangeText(text) {
setText(text)
}
return (
<>
<input type="text" value={text} onChange={e => handleChangeText(e.target.value)} />
<button onClick={() => {
setText('')
onAddTask(text)
}}>新增</button>
</>
)
}
在 TaskList 文件 中传入 最新的 tasks
以及修改onChangeTask
、删除onDeleteTask
函数
javascript
// TaskList 文件
export default function TaskList ({tasks, onChangeTask, onDeleteTask}) {
return (
<>
<ul>
{
tasks.map((itm, index) =>{
return (
<li key={itm.id}>
<span>{index + 1}</span>
<input type="text" value={itm.text} onChange={(e) => onChangeTask({...itm, text: e.target.value})}/>
<button onClick={() => onDeleteTask(itm.id)}>Delete</button>
</li>
)
})
}
</ul>
</>
)
}
useReducer 与 useState相比较
异同
1、useReducer 更倾
向于处理多逻辑
状态,useState 倾向于处理单逻辑
状态;
2、useReducer 可以处理 所有 useState 处理的 更新的属性
3、都必须
在最组件的最顶层调用
,不能
在 条件语句
或者循环中使用;
4、初始化的时候 都会被调用 两次
用于检查代码中的意外不纯粹性;
5、都可以触发视图更新
useReducer 的优缺点
优点:
代码统一组织管理 :reducer 使得状态更新逻辑更加清晰,可以将不同的更新逻辑集中在一个地方,避免了多个 useState
带来的管理混乱。
方便调试 :reducer
是一个纯函数
,给出明确的状态变化规则,便于调试 和日志 记录。
用于复杂状态管理 :对于复杂的状态更新,useReducer
是一种优于 useState
的解决方案,尤其是当状态变化需要依赖于多个值时。
缺点:
代码复杂 :与 useState 相比,useReducer 需要写更多的代码,尤其是对于简单的状态管理,它的使用可能显得有些过于复杂。
学习成本高:对于 React 新手来说,理解 reducer 函数的工作方式可能需要一些时间,尤其是对于不熟悉 Redux 的开发者。
仅代表个人观点,如有出入欢迎批评指正