React第十五节useReducer使用详解差异

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 的开发者。

仅代表个人观点,如有出入欢迎批评指正

相关推荐
FungLeo6 分钟前
成为全栈·Vue 管理后台篇·用 fetch 建一层可控的请求内核
前端·javascript·vue.js·http·fetch·formdata·接口封装
用户842981424181023 分钟前
ByteJS,让重要的 JavaScript 以字节码运行。
javascript
FungLeo2 小时前
成为全栈·Vue 管理后台篇·Vue Router如何守住多角色后台边界
前端·javascript·vue.js·rbac·vue router·路由守卫·前端权限
FungLeo2 小时前
成为全栈·Vue 管理后台篇·分页只显示第一页:从接口total 定位到前端修复
前端·vue.js·状态模式·分页·naive ui·服务端分页·前端问题排查
ZhengEnCi2 小时前
苹果滑动为什么有「肉感」:橡皮筋越界阻尼与弹簧动画的物理原理
前端
Moment3 小时前
不会后期的我,发现了一个开源胶片神器😍😍😍
前端·后端·开源
L1mbo3 小时前
Lite模式 缓解微信开发者工具卡顿,附 uni-app 实践方案
前端·微信小程序
FungLeo3 小时前
成为全栈·Vue管理后台篇·仪表盘不是几张卡片:组合统计接口与角色视图
前端·javascript·vue.js·rbac·仪表盘·管理后台·tanstack query
程序员大阳3 小时前
HTML+CSS+JS对话式实战(7)-学生端活动报名功能开发
javascript·css·html·活动报名
SameX3 小时前
HarmonyOS 做桌面卡片 onAddForm 要同步返回但数据在数据库里的解法
前端