@reduxjs/toolkit进阶指南

news2024/9/20 2:46:44

虽然@reduxjs/toolkit为Redux提供了开箱即用的最佳实践,但它也内置了一些强大的功能,可以极大简化Redux在复杂场景下的使用。本文将重点介绍以下进阶特性:
在这里插入图片描述

1.使用Immer简化不可变更新

Redux要求状态更新必须是不可变的,这意味着我们需要手动复制和更新数据,这种模式很容易出错且难以维护。@reduxjs/toolkit内置了Immer库,让我们可以像修改JavaScript对象类型数据同普通 JavaScript 对象一样去修改状态,不需要手动拷贝,数组展开等操作。

Copy code
import { createSlice } from '@reduxjs/toolkit';

const slice = createSlice({
  name: 'todos',
  initialState: [],
  reducers: {
    addTodo(state, action) {
      // 可以像普通数组一样修改状态
      state.push(action.payload);
    },
    toggleTodo(state, action) {
      const todo = state.find(todo => todo.id === action.payload);
      // 可以直接修改todo对象
      todo.completed = !todo.completed;
    }
  }
});

Immer会自动跟踪所有对状态的修改,并基于修改产生一个全新的不可变状态副本。这使我们无需手动进行深拷贝等繁琐操作。

2.处理异步任务

Redux 本身是不支持异步操作的,如我们想在redux中从接口中取一个用户信息,在不使用@reduxjs/toolkit的时候 ,传统方式中是可以通过中间件来实现异步任务。最常用的中间件就是 redux-thunk 和 redux-saga。而在@reduxjs/toolkit中,再次做了优化,可以通过createAsyncThunk工具简化了异步操作的处理。

示例:假设我们有两个异步请求,分别获取用户列表和用户详情:

import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';

// 获取用户列表
export const fetchUsers = createAsyncThunk('users/fetchAll', async () => {
  const res = await fetch('/api/users');
  return res.json();
});

// 获取用户详情
export const fetchUserDetails = createAsyncThunk('users/fetchDetails', async (userId) => {
  const res = await fetch(`/api/users/${userId}`);
  return res.json();
});

const usersSlice = createSlice({
  name: 'users',
  initialState: {
    entities: {},
    userDetails: null,
    loading: 'idle',
  },
  extraReducers: (builder) => {
    // 处理获取用户列表
    builder
      .addCase(fetchUsers.pending, (state) => {
        state.loading = 'loading';
      })
      .addCase(fetchUsers.fulfilled, (state, action) => {
        state.loading = 'idle';
        const userData = action.payload;
        state.entities = userData.reduce((obj, user) => {
          obj[user.id] = user;
          return obj;
        }, {});
      })
      .addCase(fetchUsers.rejected, (state) => {
        state.loading = 'idle';
      })
    // 处理获取用户详情
    builder 
      .addCase(fetchUserDetails.pending, (state) => {
        state.loading = 'loading';
      })
      .addCase(fetchUserDetails.fulfilled, (state, action) => {
        state.loading = 'idle';
        state.userDetails = action.payload;
      })
      .addCase(fetchUserDetails.rejected, (state) => {
        state.loading = 'idle';
      })
  }  
});

export const { } = usersSlice.actions;
export default usersSlice.reducer;

总结:
使用 createAsyncThunk 创建一个异步 thunk,在 extraReducers 中处理异步 action 的不同状态。相比手写 action creators 和 reducers,这种方式更加集中和简洁。

  1. 为每个异步请求创建一个 createAsyncThunk 在 extraReducers 中,使用 builder.addCase
  2. 分别处理每个异步请求的 pending/fulfilled/rejected 状态 根据需求在不同状态下更新 state
  3. 可以通过在组件中分发不同的异步 thunk 来触发对应的异步请求。通过这种方式,可以集中处理多个异步请求的不同状态和效果。当然,如果异步请求逻辑过于复杂,你也可以考虑使用 Redux-Saga 或 Redux-Observable 这样的库来管理异步流程。但对于大多数场景,createAsyncThunk 已经足够强大并且易于使用了。

3. 可复用选择器

@reduxjs/toolkit 中的 createSelector 类似于 Vuex 中的 getters,它们的作用和使用方式有一些相似之处。

简单来说,createSelector 主要用于创建可复用和高效的派生状态选择器(derived state selectors)。这些选择器可以基于 Redux store 中的状态计算出其他衍生数据,类似于 Vue 组件中的计算属性。

与 Vuex getters 类似,createSelector 可以让我们避免在多个组件中重复相同的衍生数据计算逻辑。它还内置了缓存和可组合的功能,可以进一步提高选择器的性能。

下面是一个简单的例子:

import { createSelector } from '@reduxjs/toolkit';

// 一个简单的选择器
const selectUsers = state => state.users.data;

// 基于 selectUsers 创建一个衍生选择器
const selectActiveUsers = createSelector(
  selectUsers,
  (users) => users.filter(user => user.active)
);

// 组合多个选择器
const selectActiveUserNames = createSelector(
  selectActiveUsers,
  (activeUsers) => activeUsers.map(user => user.name)
);

在这个例子中:

  • selectUsers 是一个简单的选择器函数,返回 state.users.data。
  • selectActiveUsers 是一个衍生选择器,基于 selectUsers 的结果计算出活跃用户列表。
  • selectActiveUserNames 是另一个衍生选择器,基于 selectActiveUsers 的结果计算出活跃用户的名字列表。

使用 createSelector 的好处是:

  1. 可以提取和复用衍生数据计算逻辑,避免重复代码。
  2. 内置缓存和可组合机制,只在输入发生变化时重新计算,提高性能。
  3. 代码结构更清晰,更易于维护和测试。

虽然 createSelector 和 Vuex getters 在实现细节上有所不同,但它们的设计理念和使用目的是类似的,都是为了更好地管理和复用衍生状态数据。

4.总结

@reduxjs/toolkit中的三个进阶用法:

  1. 使用Immer简化不可变更新

Redux要求状态更新必须是不可变的,传统做法需要手动拷贝对象/数组进行修改。@reduxjs/toolkit内置了Immer库,让我们可以像修改普通 JavaScript 对象一样直接修改状态,而不必手动拷贝。

const slice = createSlice({
  reducers: {
    addTodo(state, action) {
      // 可以像普通数组一样直接修改状态
      state.push(action.payload);
    }
  }
});

Immer会跟踪所有对状态的修改,在最后得到一个全新的不可变状态副本,简化了不可变更新的过程。

  1. 处理异步更新

@reduxjs/toolkit通过createAsyncThunk简化了异步操作的处理。

const fetchData = createAsyncThunk('data/fetch', async () => {
  const res = await fetch('/api/data');
  return res.json();
});

const slice = createSlice({
  extraReducers: (builder) => {
    builder
      .addCase(fetchData.pending, (state) => {...})
      .addCase(fetchData.fulfilled, (state, action) => {...})
      .addCase(fetchData.rejected, (state, action) => {...})
  }
});

createAsyncThunk会为异步操作自动生成 pending/fulfilled/rejected 的 action type,我们只需在 extraReducers 中处理不同状态即可,避免了手写 action creators 的繁琐。

  1. 创建可复用选择器

@reduxjs/toolkit提供了createSelector来创建可组合的派生状态选择器。

const selectUserIds = state => Object.keys(state.users.entities);
const selectUserEntities = state => state.users.entities;

const selectAllUsers = createSelector(
  [selectUserIds, selectUserEntities],
  (userIds, userEntities) => userIds.map(id => userEntities[id])
);

createSelector会对输入进行缓存和可组合化处理,使得选择器可以高效地重用之前的结果,提取和复用衍生数据计算逻辑。

通过这三个进阶用法,@reduxjs/toolkit进一步简化和优化了Redux的使用,提高了开发效率和代码质量。它们建立在Redux的核心理念之上,但提供了更多的抽象和工具,使得状态管理变得更加高效和可维护。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1612026.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ubuntu 微调训练ChatGLM3大语言模型

Ubuntu 微调训练ChatGLM3大语言模型 LLaMA Factory 的 LoRA 微调提供了 3.7 倍的加速比,同时在广告文案生成任务上取得了更高的 Rouge 分数。结合 4 比特量化技术,LLaMA Factory 的 QLoRA 微调进一步降低了 GPU 显存消耗。 https://github.com/hiyouga…

天星金融(原小米金融)履行社会责任,提高社保政策知晓度

二十大报告指出“为民造福是立党为公、执政为民的本质要求“,人民幸福安康是推动高质量发展的最终目的。社会保障作为维护社会公平、增进人民福祉的基本制度,既是“安全网”也是“稳定器”,发挥着改善民生的重要作用。为进一步提升人民群众对…

接雨水 , 给定二维图,能容多少水

42. 接雨水 - 力扣(LeetCode) 看着就是非常常规的题目,所以非常有必要掌握。 最少也把O(n^2)的方法写出来吧。力扣官方题解的三种方法O(n)都挺好,不过可能有点难读,在此…

淘宝购物更智能:taobao.item_search API接口实现关键字精准匹配

随着电子商务的飞速发展,淘宝作为中国最大的网络购物平台之一,为亿万消费者提供了便捷、丰富的购物体验。然而,在海量商品中快速找到符合自己需求的商品,一直是消费者面临的挑战。为了提升购物体验,淘宝开放平台提供了…

渐进式交付实践:通过 Argo Rollouts 和 FSM Gateway 实现金丝雀发布

渐进式交付(Progressive delivery)是一种软件发布策略,旨在更安全、更可控地将新版本软件逐步推出给用户。它是持续交付的进一步提升,允许开发团队在发布新版本时拥有更细粒度的控制,例如可以根据用户反馈、性能指标和…

树莓派3B长时间不操作屏幕息屏无信号处理

树莓派外接显示器,需长时间展示某个网页,经过一段时间,显示器屏幕会黑掉显示无信号。 需修改 /etc/lightdm/lightdm.conf 配置文件中新增如下两行并重启。 xserver-commandX -s 0 dpms sleep-inactive-timeout0

系统架构设计精华知识

数据流风格:适合于分阶段做数据处理,交互性差,包括:批处理序列、管理过滤器。调用/返回风格:一般系统都要用到,包括:主程序/子程序,面向对象,层次结构(分层越…

图像分类:Pytorch实现Vision Transformer(ViT)进行图像分类

图像分类:Pytorch实现Vision Transformer(ViT)进行图像分类 前言相关介绍ViT模型的基本原理:ViT的特点与优势:ViT的缺点:应用与拓展: 项目结构具体步骤准备数据集读取数据集设置并解析相关参数定…

人工智能论文GPT-3(3):2020.5 Language Models are Few-Shot Learners;架构;训练数据集;开源

2.1 模型与架构 我们使用了与GPT-2相同的模型和架构,包括其中描述的改进初始化、预归一化和可逆分词技术,但有所不同的是,我们在Transformer的各层中使用了交替的密集和局部带状稀疏注意力模式,类似于Sparse Transformer 。为了研…

RocketMQ异步消息发送失败重试DEMO

producer.setRetryTimesWhenSendAsyncFailed(3); 都知道通过设置,尝试是在MQClientAPIImpl 中完成 其重试是通过MQClientAPIImpl的onExceptionImpl方法来实现,它会先判断重试次数,然后重新调用sendMessageAsync方法进行重试,调用…

【氧化镓】Ga2O3 MOSFET器件的单SEB机制TCAD研究

本文是一篇关于氧化镓(Ga2O3)金属氧化物半导体场效应晶体管(MOSFET)在单粒子烧毁(single event burnout, SEB)事件中的机制研究的文章。文章通过使用技术计算机辅助设计(TCAD)模拟来探究侧向耗尽型氧化镓MOSFET设备在SEB中的敏感区域和安全操作电压,并提出了辐射损伤…

Linux环境变量深度解析

文章目录 一、引言二、环境变量的基本概念1、环境变量的定义2、环境变量的作用与意义 三、环境变量的导入1、导入所需文件2、登陆时的导入 四、环境变量的设置方法1、查看环境变量的方式2、使用export命令临时设置环境变量3、修改配置文件以永久设置环境变量 五、命令行参数与环…

用户的流失预测分析

项目背景 随着电信行业的持续发展,运营商们开始更加关注如何扩大他们的客户群体。研究表明,获取新客户所需的成本要远高于保留现有客户的成本。因此,在激烈的竞争中,保留现有客户成为了一个巨大的挑战。在电信行业中,…

ADSP-21479的开发详解五(AD1939 C Block-Based Talkthru 48 or 96 kHz)音频直通

硬件准备 ADSP-21479EVB开发板: 产品链接:https://item.taobao.com/item.htm?id555500952801&spma1z10.5-c.w4002-5192690539.11.151441a3Z16RLU AD-HP530ICE仿真器: 产品链接:https://item.taobao.com/item.htm?id38007…

AI大模型日报#0420:开源模型击败GPT-4、西湖大学蛋白质通用大模型、GPT的七条经验

导读: 欢迎阅读《AI大模型日报》,内容基于Python爬虫和LLM自动生成。目前采用“文心一言”生成了每条资讯的摘要。 标题: 开源模型打败GPT-4!LLM竞技场最新战报,Cohere Command R上线 摘要: GPT-4在LLM竞技场被开源模型Cohere的…

算法课程笔记——集合set

3复杂度不稳定 删一个和删除全部 注意iter是类 遍历是无序的

AI时代,操作系统交互的革命性变革

AI时代对操作系统交互的影响 对于2024年的智能手机厂商们来说,在冲击高端市场的路上有一场绝对输不起的硬仗,那就是AI大模型的落地之战。 OpenAI的ChatGPT引爆了全球AIGC(生成式人工智能)热潮,短短一年时间里&#xff…

使用Python爬取易车网汽车信息(含x-sign参数逆向分析)

文章目录 1. 写在前面2. 接口分析3. 断点分析3. 算法还原 【🏠作者主页】:吴秋霖 【💼作者介绍】:擅长爬虫与JS加密逆向分析!Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致…

【论文精读】Attention is all you need

摘要 主要的序列转换模型是基于复杂的循环或卷积神经网络,其中包括一个编码器和一个解码器。性能最好的模型还通过一种注意力机制将编码器和解码器连接起来。我们提出了一种新的简单的网络架构,Transformer,完全基于注意机制,完全…

C++设计模式:适配器模式(十四)

1、定义与动机 定义:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的哪些类可以一起工作。 动机: 在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境…