我今天分分钟就理解了react中的reducer

什么是 reducer 函数? 为什么要用 reducer?

  • Reducer 是处理状态的另一种方式。通俗来讲,就是可以让你的复杂组件更加干净,代码更加优雅
  • 当你的组件里有好多个状态更新逻辑,并且有些是有一定关联性的,写多个useState会看起来很杂乱,为解决这个问题,我们可以将多个状态更新逻辑整合到一个外部函数,这个函数就是reducer
  • 整合业务逻辑

使用 reducer 整合状态逻辑

举个栗子:


从上图我们可以看到,目前这个组件有三个处理逻辑,我们写了三个处理函数,这个组件的每个事件处理程序都通过 setTasks 来更新状态。随着这个组件的不断迭代,其状态逻辑也会越来越多。现在看起来没有什么毛病,但是真实业务场景里,需求往往会更加复杂,我们可以使用下面的方式来让业务逻辑更加清晰明了:

将状态逻辑移到组件之外 reducer 函数中

  • 将设置状态的逻辑 修改 成 dispatch 的一个 action;
  • 编写 一个 reducer 函数;
  • 在你的组件中 使用 reducer

看了上面我画的图,是不是感觉reducer很简单哇~ 在真实项目中,我们通常会使用 switch 语句来编写reducer,就像下图

既然我们会写了,那该怎么使用呢?

代码

tasksReducer.js

export default function tasksReducer(tasks, action) {
  switch (action.type) {
    case 'added': {
      return [
        ...tasks,
        {
          id: action.id,
          text: action.text,
          done: false,
        },
      ];
    }
    case 'changed': {
      return tasks.map((t) => {
        if (t.id === action.task.id) {
          return action.task;
        } else {
          return t;
        }
      });
    }
    case 'deleted': {
      return tasks.filter((t) => t.id !== action.id);
    }
    default: {
      throw Error('未知 action:' + action.type);
    }
  }
}

App.js

import { useReducer } from 'react';
import AddTask from './AddTask.js';
import TaskList from './TaskList.js';
import tasksReducer from './tasksReducer.js';

export default function TaskApp() {
  const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);

  function handleAddTask(text) {
    dispatch({
      type: 'added',
      id: nextId++,
      text: text,
    });
  }

  function handleChangeTask(task) {
    dispatch({
      type: 'changed',
      task: task,
    });
  }

  function handleDeleteTask(taskId) {
    dispatch({
      type: 'deleted',
      id: taskId,
    });
  }

  return (
    <>
      <h1>我今天要做什么呢?</h1>
      <AddTask onAddTask={handleAddTask} />
      <TaskList
        tasks={tasks}
        onChangeTask={handleChangeTask}
        onDeleteTask={handleDeleteTask}
      />
    </>
  );
}

let nextId = 3;
const initialTasks = [
  {id: 0, text: '吃饭', done: true},
  {id: 1, text: '睡觉', done: false},
  {id: 2, text: '打豆豆', done: false},
];

对比 useState 和 useReducer

我们观察上图,不难发现:

  • 参数:useReducer 和 useState 很相似,都有初始状态,useReducer 钩子接受 2 个参数: reducer 函数,初始的 state
  • 返回值:useReducer 会返回一个有状态的值和一个设置该状态的函数(在上面案例中就是 dispatch 函数)
  • 代码体积: 多事件相似方式修改 state 时,useReducer 可减少代码量
  • 可读性: 状态更新逻辑简单我们就可以用useState ,逻辑复杂,useReducer 可以将状态更新逻辑与事件处理程序分离
  • 可调试性: useState 出现问题不太好调试,而使用 useReducer 时, 可以在 reducer 函数打印日志

如何编写一个优雅的 reducer

  • reducers 必须纯粹。 即当输入相同时,输出也是相同的。它们不应该包含异步请求、定时器或者任何副作用(对组件外部有影响的操作)。
  • 每个 action 都描述了一个单一的用户交互,即使它会引发数据的多个变化。 举个例子,如果用户在一个由 reducer 管理的表单(包含五个表单项)中点击了 重置按钮,那么 dispatch 一个 reset_form 的 action 比 dispatch 五个单独的 set_field 的 action 更加合理。

还可以使用 Immer 简化 reducers

useImmerReducer 让你可以通过 push 或 arr[i] = 来修改 state。下图描述了,优化前后,代码确实有所减少哦~~

Reducers 应该是纯净的,而 Immer 提供了一种特殊的 draft 对象,可以通过它安全修改 state。Immer 在底层基于当前 state 创建一个副本。

今天就写到这里啦~

  • 小伙伴们,( ̄ω ̄( ̄ω ̄〃 ( ̄ω ̄〃)ゝ我们明天再见啦~~
  • 大家要天天开心哦

欢迎大家指出文章需要改正之处~
学无止境,合作共赢

在这里插入图片描述

欢迎路过的小哥哥小姐姐们提出更好的意见哇~~

posted @   糖~豆豆  阅读(275)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
历史上的今天:
2021-06-09 解决前端发送post 请求出现403,cancled等问题
2021-06-09 NG-ZORRO + Angular11使用Echarts实现柱折线图-折柱混合,并给图表添加点击打印图表数据!!!详细代码
2021-06-09 NG-Alain + Angular11使用ModalHelper实现简单版本弹框,代码超级少,记得模块要引用这个组件
Live2D
欢迎阅读『我今天分分钟就理解了react中的reducer』
点击右上角即可分享
微信分享提示