当前位置: 首页 > news >正文

【React】状态管理之Redux


鑫宝Code

🌈个人主页: 鑫宝Code
🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础
💫个人格言: "如无必要,勿增实体"


文章目录

  • 状态管理之Redux
    • 引言
    • 1. Redux 的核心概念
      • 1.1 单一数据源(Single Source of Truth)
      • 1.2 State 是只读的
      • 1.3 使用纯函数执行修改
    • 2. Redux 工作流程
      • 2.1 数据流向
      • 2.2 中间件机制
    • 3. Redux 内部实现原理
      • 3.1 createStore 的实现
      • 3.2 combineReducers 的实现
    • 4. Redux 性能优化
      • 4.1 reselect 的使用
      • 4.2 不可变性的保持
    • 5. 实际应用中的最佳实践
      • 5.1 Action 创建函数
      • 5.2 异步 Action 处理
    • 总结

状态管理之Redux

在这里插入图片描述

引言

Redux 作为一个优秀的状态管理工具,在 React 生态系统中占据着重要地位。本文将深入探讨 Redux 的核心工作原理,帮助开发者更好地理解和使用这个工具。

1. Redux 的核心概念

1.1 单一数据源(Single Source of Truth)

Redux 使用单一的 store 来存储应用的所有状态。这意味着:

  • 整个应用的状态被存储在一个对象树中
  • 这个对象树只存在于唯一的 store 中
  • 状态是只读的,唯一改变状态的方式是触发 action
const store = {todos: [],visibilityFilter: 'SHOW_ALL',user: {id: null,name: null}
}

1.2 State 是只读的

在 Redux 中,改变状态的唯一方式是触发(dispatch)一个 action。这确保了:

  • 视图和网络请求都不能直接修改状态
  • 所有的修改都被集中化处理
  • 修改都是按顺序一个接一个地执行
// Action 的结构
const action = {type: 'ADD_TODO',payload: {text: '学习 Redux',completed: false}
}

1.3 使用纯函数执行修改

Reducer 是一个纯函数,它接收先前的状态和一个 action,返回新的状态:

const todoReducer = (state = [], action) => {switch (action.type) {case 'ADD_TODO':return [...state, action.payload]case 'TOGGLE_TODO':return state.map(todo =>todo.id === action.payload.id? { ...todo, completed: !todo.completed }: todo)default:return state}
}

2. Redux 工作流程

在这里插入图片描述

2.1 数据流向

Redux 采用严格的单向数据流,主要包含以下步骤:

  1. 用户在界面触发事件
  2. 调用 dispatch(action)
  3. Redux store 调用 reducer 函数
  4. Root reducer 把多个子 reducer 输出合并成一个单一的状态树
  5. Redux store 保存了 reducer 返回的完整状态树

2.2 中间件机制

中间件提供了一个分类处理 action 的机制:

// 中间件示例
const logger = store => next => action => {console.log('dispatching', action)let result = next(action)console.log('next state', store.getState())return result
}

3. Redux 内部实现原理

3.1 createStore 的实现

createStore 是 Redux 最核心的 API:

function createStore(reducer, preloadedState, enhancer) {let currentReducer = reducerlet currentState = preloadedStatelet currentListeners = []function getState() {return currentState}function subscribe(listener) {currentListeners.push(listener)return function unsubscribe() {const index = currentListeners.indexOf(listener)currentListeners.splice(index, 1)}}function dispatch(action) {currentState = currentReducer(currentState, action)currentListeners.forEach(listener => listener())return action}return {getState,subscribe,dispatch}
}

3.2 combineReducers 的实现

combineReducers 用于合并多个 reducer:

function combineReducers(reducers) {return function combination(state = {}, action) {const nextState = {}let hasChanged = falsefor (let key in reducers) {const reducer = reducers[key]const previousStateForKey = state[key]const nextStateForKey = reducer(previousStateForKey, action)nextState[key] = nextStateForKeyhasChanged = hasChanged || nextStateForKey !== previousStateForKey}return hasChanged ? nextState : state}
}

4. Redux 性能优化

在这里插入图片描述

4.1 reselect 的使用

使用 reselect 可以避免不必要的重复计算:

import { createSelector } from 'reselect'const getTodos = state => state.todos
const getVisibilityFilter = state => state.visibilityFilterconst getVisibleTodos = createSelector([getTodos, getVisibilityFilter],(todos, filter) => {switch (filter) {case 'SHOW_ALL':return todoscase 'SHOW_COMPLETED':return todos.filter(t => t.completed)case 'SHOW_ACTIVE':return todos.filter(t => !t.completed)}}
)

4.2 不可变性的保持

确保状态更新的不可变性是 Redux 性能优化的关键:

// 不推荐
state.todos[0].completed = true// 推荐
return {...state,todos: state.todos.map((todo, index) =>index === 0 ? { ...todo, completed: true } : todo)
}

5. 实际应用中的最佳实践

5.1 Action 创建函数

使用 action 创建函数来生成 action:

const addTodo = text => ({type: 'ADD_TODO',payload: {id: nextTodoId++,text,completed: false}
})

5.2 异步 Action 处理

使用 redux-thunk 处理异步操作:

const fetchTodos = () => {return async dispatch => {dispatch({ type: 'FETCH_TODOS_REQUEST' })try {const response = await api.fetchTodos()dispatch({type: 'FETCH_TODOS_SUCCESS',payload: response.data})} catch (error) {dispatch({type: 'FETCH_TODOS_FAILURE',error: error.message})}}
}

总结

Redux 通过其简单而强大的设计原则,为 React 应用提供了可预测的状态管理能力。理解其工作原理对于构建大型应用至关重要。核心要点包括:

  • 单一数据源
  • 状态只读
  • 使用纯函数进行修改
  • 单向数据流
  • 中间件机制

通过合理运用这些原则,我们可以构建出更加可维护和可扩展的应用。同时,通过使用 reselect、保持不可变性等优化手段,还能确保应用具有良好的性能表现。

End

相关文章:

【React】状态管理之Redux

🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 ​💫个人格言: "如无必要,勿增实体" 文章目录 状态管理之Redux引言1. Redux 的核心概念1.1 单一数据源(Single Sou…...

3195. 有趣的数-13年12月CCF计算机软件能力认证(组合数)

题目 思路 统计方案的时候先去分类,先放01,然后在考虑23对于第k类, 对于01的选择 对于所有的分类:本题我觉得要考虑的几个点就是:状态分类得到数学公式组合数的计算防越界处理 代码 计算组合数的代码模板&#xff1…...

基于 Python 的 Bilibili 评论分析与可视化

一、项目概述 本项目利用 Python 对 Bilibili (哔哩哔哩)平台上的视频评论数据进行爬取、清洗和分析,并通过可视化展示数据的主要特征。我们通过以下几个步骤实现了这一过程: 数据爬取:使用 Bilibili 提供的 API 获取…...

大语言模型理论基础

文章目录 前言大语言模型必需知识概述大语言模型目标模型上下文神经网络的神经元常见激活函数SigmoidTanhRelusoftmax 通用近似定理多层感知机(MLP)拟合最后 前言 你好,我是醉墨居士,我们接下来对大语言模型一探究竟,…...

【 LLM论文日更|检索增强:大型语言模型是强大的零样本检索器 】

论文:https://aclanthology.org/2024.findings-acl.943.pdf代码:GitHub - taoshen58/LameR机构:悉尼科技大学 & 微软 & 阿姆斯特丹大学 & 马里兰大学领域:retrieval & llm发表:ACL2024 研究背景 研究…...

【基于轻量型架构的WEB开发】课程 作业3 Spring框架

一. 单选题(共12题,48分) 1. (单选题)以下有关Spring框架优点的说法不正确的是( )。 A. Spring就大大降低了组件之间的耦合性。 B. Spring是一种侵入式框架 C. 在Spring中,可以直接通过Spring配置文件管理…...

14.最长公共前缀-力扣(LeetCode)

题目: 解题思路: 解决本题的关键点是确定扫描的方式,大体上有两种方式:横向扫描和纵向扫描。 1、横向扫描:首先比较第一个字符串和第二个字符串,记录二者的公共前缀,然后用当前公共前缀与下一个…...

客户案例|智能进化:通过大模型重塑企业智能客服体验

01 概 述 随着人工智能技术的快速发展,客户对服务体验的期待和需求不断升级。在此背景下,大模型技术的崛起,为智能客服领域带来了创造性的变革。 在上篇文章《在后LLM时代,关于新一代智能体的思考》中有提到,智能客服…...

Flink Job更新和恢复

Checkpoints 的主要目的是为意外失败的作业提供恢复机制。 Savepoints的设计更侧重于可移植性和操作灵活性,尤其是在 job 变更方面。Savepoint 的用例是针对计划中的、手动的运维。例如,可能是更新你的 Flink 版本,更改你的作业图等等。 fli…...

读多写少业务中,MySQL如何优化数据查询方案?

小熊学Java​站点:https://www.javaxiaobear.cn 编程资料合集:https://pqgmzk7qbdv.feishu.cn/base/QXq2bY5OQaZiDksJfZMc30w5nNb?from=from_copylink 看一看当面试官提及“在读多写少的网络环境下,MySQL 如何优化数据查询方案”时,你要从哪些角度出发回答问题??? 案例…...

Bugku CTF_Web——点login咋没反应

Bugku CTF_Web——点login咋没反应 进入靶场 随便输个试试 看来确实点login没反应 抓包看看 也没有什么信息 看了下源码 给了点提示 一个admin.css try ?12713传参试试 拿到一个php代码 <?php error_reporting(0); $KEYctf.bugku.com; include_once("flag.php&q…...

attention 注意力机制 学习笔记-GPT2

注意力机制 这可能是比较核心的地方了。 gpt2 是一个decoder-only模型&#xff0c;也就是仅仅使用decoder层而没有encoder层。 decoder层中使用了masked-attention 来进行注意力计算。在看代码之前&#xff0c;先了解attention-forward的相关背景知识。 在普通的self-atten…...

什么是HTTP,什么是HTTPS?HTTP和HTTPS都有哪些区别?

什么是 HTTP&#xff1f; HTTP&#xff08;Hypertext Transfer Protocol&#xff0c;超文本传输协议&#xff09;是一种应用层协议&#xff0c;用于在互联网上进行数据通信。它定义了客户端&#xff08;通常是浏览器&#xff09;和服务器之间的请求和响应格式。HTTP 是无状态的…...

SkyWalking-安装

SkyWalking-简单介绍 是一个开源的分布式追踪系统&#xff0c;用于检测、诊断和优化分布式系统的功能。 支持 ElasticSearch、H2、MySQL、PostgreSql 等数据库 基于 ElasticSearch 的情况 ElasticSearch&#xff08;ES&#xff09; 安装 1、下载并解压 https://www.elastic…...

RabbitMQ运维

1. 单机多节点 1.1 搭建RabbitMQ ①安装RabbitMQ 略 ②确认RabbitMQ运⾏没问题 #查看RabbitMQ状态 rabbitmqctl status 节点名称: 端口号: 25672:Erlang分布式节点通信的默认端⼝, Erlang是RabbitMQ的底层通信协议.15672: Web管理界⾯的默认端⼝, 通过这个端⼝可以访问R…...

Go语言并发精髓:深入理解和运用go语句

Go语言并发精髓:深入理解和运用go语句 在Go语言的世界里,go语句是实现并发的核心,它简洁而强大,允许程序以前所未有的方式运行多个任务。本文将深入探讨go语句及其执行规则,揭示Go语言并发编程的内在机制,并提供实际案例帮助读者掌握其用法。 1. go语句的基本概念(Wha…...

基于STM32的智能家居系统:MQTT、AT指令、TCP\HTTP、IIC技术

一、项目概述 随着智能家居技术的不断发展&#xff0c;越来越多的家庭开始使用智能设备来提升生活质量和居住安全性。智能家居系统不仅提供了便利的生活方式&#xff0c;还能有效地监测家庭环境&#xff0c;保障家庭安全。本项目以设计一种基于STM32单片机的智能家居系统为目标…...

分糖果(相等分配)

题目&#xff1a;有n种不同口味的糖果&#xff0c;第i种糖果的数量为a[i]&#xff0c;现在需要把糖果分给m个人。分给每个人糖果的数量必须是相等的&#xff0c;并且每个人只能选择一种糖果。也就是说&#xff0c;可以把一种糖果分给多个人&#xff0c;但是一个人的糖果不能有多…...

docker构建jdk11

# 建立一个新的镜像文件&#xff0c;配置模板&#xff1a;新建立的镜像是以centos为基础模板 # 因为jdk必须运行在操作系统之上 FROM centos:7.9.2009# 作者名 MAINTAINER yuanhang# 创建一个新目录来存储jdk文件 RUN mkdir /usr/local/java#将jdk压缩文件复制到镜像中&#…...

唐帕科技校园语音报警系统:通过关键词识别,阻止校园霸凌事件

校园霸凌问题已成为全球教育领域的严峻挑战&#xff0c;给受害者带来了身心上的长期创伤。然而&#xff0c;随着科技的发展&#xff0c;尤其是人工智能和语音识别技术的不断进步&#xff0c;我们开始看到创新性解决方案的出现。校园语音报警系统便是其中一种利用技术手段保护学…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

基于当前项目通过npm包形式暴露公共组件

1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹&#xff0c;并新增内容 3.创建package文件夹...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

【git】把本地更改提交远程新分支feature_g

创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险

C#入门系列【类的基本概念】&#xff1a;开启编程世界的奇妙冒险 嘿&#xff0c;各位编程小白探险家&#xff01;欢迎来到 C# 的奇幻大陆&#xff01;今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类&#xff01;别害怕&#xff0c;跟着我&#xff0c;保准让你轻松搞…...