Redux记录:Store是如何自动调用reducers来处理action的

2024-05-14 03:48

本文主要是介绍Redux记录:Store是如何自动调用reducers来处理action的,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Redux记录:Store是如何自动调用reducers来处理action的

作为一个后端程序员,经常也要写一点前端、维护一下前端。因此一直在与前端打交道,但是一直没有理解当用户操作view通过dispatch发出 action之后,我们定义的一系列的reducer是如何来自动执行处理的。

先说结论:当用户操作view之后发出一个action,store会遍历所有的reducers来依次处理这个action来改变state。

今天浏览自己所在公司的官方博客,发现了这篇文章:Redux从设计到源码,仔细拜读了一下,收获很大,也解决了自己一直以来的困惑。

借此机会,自己也梳理一下。

在前端代码,自己经常看到类似如下的代码:

    let store = createStore(reducers, undefined, compose(applyMiddleware(thunk,fetchMiddleware),window.devToolsExtension ? window.devToolsExtension() : f => f));

其中,reducers如下:

    let reducers = combineReducers({AReducer, BReducer,CReducer});//AReducer等是我们自己定义的reducer

那么,当一个type=“A”的action产生后,是如何去这些{AReducer, BReducer,CReducer}来匹配查找然后进行处理的呢?自己当时的猜想是遍历所有的,看了源码之后原来真的是这样。

combineReducers

先看combineReducers的源码里面做了些什么,源码如下:

    export default function combineReducers(reducers) {const reducerKeys = Object.keys(reducers)const finalReducers = {}for (let i = 0; i < reducerKeys.length; i++) {const key = reducerKeys[i]if (process.env.NODE_ENV !== 'production') {if (typeof reducers[key] === 'undefined') {warning(`No reducer provided for key "${key}"`)}}if (typeof reducers[key] === 'function') {finalReducers[key] = reducers[key]}}const finalReducerKeys = Object.keys(finalReducers)let unexpectedKeyCacheif (process.env.NODE_ENV !== 'production') {unexpectedKeyCache = {}}let shapeAssertionErrortry {assertReducerShape(finalReducers)} catch (e) {shapeAssertionError = e}//返回的是如下这个函数,用于处理actionreturn function combination(state = {}, action) {if (shapeAssertionError) {throw shapeAssertionError}if (process.env.NODE_ENV !== 'production') {const warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache)if (warningMessage) {warning(warningMessage)}}let hasChanged = falseconst nextState = {}for (let i = 0; i < finalReducerKeys.length; i++) {const key = finalReducerKeys[i]const reducer = finalReducers[key]const previousStateForKey = state[key]const nextStateForKey = reducer(previousStateForKey, action)if (typeof nextStateForKey === 'undefined') {const errorMessage = getUndefinedStateErrorMessage(key, action)throw new Error(errorMessage)}nextState[key] = nextStateForKeyhasChanged = hasChanged || nextStateForKey !== previousStateForKey}return hasChanged ? nextState : state}}

上面的代码比较长,只需要注意两点即可:

1、将一系列的reducer以(reducerKey,reducer)存储在finalReducers中。

2、返回的函数将在store中自动调用,来处理action。至于如何处理的,下面分析完createStore之后将会分析。

createStore

下面是createStore方法的部分源码,由于store.dispatch(action)是用来分发action,这是修改state的唯一方式,基于此我们这里只关注dispatch方法,因此只对其进行了保留,如果想对其他方法有了解,可以参考博文:Redux从设计到源码,

    export default function createStore(reducer, preloadedState, enhancer) {//省略类型检查      let currentReducer = reducerlet currentState = preloadedStatelet currentListeners = []let nextListeners = currentListenerslet isDispatching = false//省略其他方法,只保留了dispatch方法   function dispatch(action) {//省略了类型检查   try {isDispatching = truecurrentState = currentReducer(currentState, action) //分析} finally {isDispatching = false}const listeners = currentListeners = nextListenersfor (let i = 0; i < listeners.length; i++) {const listener = listeners[i]listener()}return action}}

store.dispatch()方法总结:

1、调用Reducer,传参(currentState,action)。

2、按顺序执行listener。

3、返回action。

下面分析第一点:调用Reducer,传参(currentState,action),即如下这行代码

currentState = currentReducer(currentState, action) 

前面我们说过,currentReducer所指的就是由这行代码let reducers = combineReducers({AReducer, BReducer,CReducer});所产生的reducers,这个reducers是如下这个函数:

    function combination(state = {}, action) {//省略了部分检查代码let hasChanged = falseconst nextState = {}//对所有的reducers进行遍历来处理action。for (let i = 0; i < finalReducerKeys.length; i++) {const key = finalReducerKeys[i]const reducer = finalReducers[key]const previousStateForKey = state[key]//利用这个reducer来处理actionconst nextStateForKey = reducer(previousStateForKey, action)if (typeof nextStateForKey === 'undefined') {const errorMessage = getUndefinedStateErrorMessage(key, action)throw new Error(errorMessage)}//保存state并判断状态是否改变了。nextState[key] = nextStateForKeyhasChanged = hasChanged || nextStateForKey !== previousStateForKey}return hasChanged ? nextState : state} 

上面比较简单哈,看完这里的源码是不是就理解了,当用户操作view产生一个action之后,store是如何自动调用reducers来处理action的哈。

这篇关于Redux记录:Store是如何自动调用reducers来处理action的的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/987666

相关文章

SpringBoot结合Docker进行容器化处理指南

《SpringBoot结合Docker进行容器化处理指南》在当今快速发展的软件工程领域,SpringBoot和Docker已经成为现代Java开发者的必备工具,本文将深入讲解如何将一个SpringBo... 目录前言一、为什么选择 Spring Bootjavascript + docker1. 快速部署与

Python使用vllm处理多模态数据的预处理技巧

《Python使用vllm处理多模态数据的预处理技巧》本文深入探讨了在Python环境下使用vLLM处理多模态数据的预处理技巧,我们将从基础概念出发,详细讲解文本、图像、音频等多模态数据的预处理方法,... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核

SpringBoot+Docker+Graylog 如何让错误自动报警

《SpringBoot+Docker+Graylog如何让错误自动报警》SpringBoot默认使用SLF4J与Logback,支持多日志级别和配置方式,可输出到控制台、文件及远程服务器,集成ELK... 目录01 Spring Boot 默认日志框架解析02 Spring Boot 日志级别详解03 Sp

Spring Boot @RestControllerAdvice全局异常处理最佳实践

《SpringBoot@RestControllerAdvice全局异常处理最佳实践》本文详解SpringBoot中通过@RestControllerAdvice实现全局异常处理,强调代码复用、统... 目录前言一、为什么要使用全局异常处理?二、核心注解解析1. @RestControllerAdvice2

Java中调用数据库存储过程的示例代码

《Java中调用数据库存储过程的示例代码》本文介绍Java通过JDBC调用数据库存储过程的方法,涵盖参数类型、执行步骤及数据库差异,需注意异常处理与资源管理,以优化性能并实现复杂业务逻辑,感兴趣的朋友... 目录一、存储过程概述二、Java调用存储过程的基本javascript步骤三、Java调用存储过程示

在Spring Boot中集成RabbitMQ的实战记录

《在SpringBoot中集成RabbitMQ的实战记录》本文介绍SpringBoot集成RabbitMQ的步骤,涵盖配置连接、消息发送与接收,并对比两种定义Exchange与队列的方式:手动声明(... 目录前言准备工作1. 安装 RabbitMQ2. 消息发送者(Producer)配置1. 创建 Spr

浏览器插件cursor实现自动注册、续杯的详细过程

《浏览器插件cursor实现自动注册、续杯的详细过程》Cursor简易注册助手脚本通过自动化邮箱填写和验证码获取流程,大大简化了Cursor的注册过程,它不仅提高了注册效率,还通过友好的用户界面和详细... 目录前言功能概述使用方法安装脚本使用流程邮箱输入页面验证码页面实战演示技术实现核心功能实现1. 随机

Python中Tensorflow无法调用GPU问题的解决方法

《Python中Tensorflow无法调用GPU问题的解决方法》文章详解如何解决TensorFlow在Windows无法识别GPU的问题,需降级至2.10版本,安装匹配CUDA11.2和cuDNN... 当用以下代码查看GPU数量时,gpuspython返回的是一个空列表,说明tensorflow没有找到

python如何调用java的jar包

《python如何调用java的jar包》这篇文章主要为大家详细介绍了python如何调用java的jar包,文中的示例代码简洁易懂,具有一定的借鉴价值,有需要的小伙伴可以参考一下... 目录一、安装包二、使用步骤三、代码演示四、自己写一个jar包五、打包步骤六、方法补充一、安装包pip3 install

k8s上运行的mysql、mariadb数据库的备份记录(支持x86和arm两种架构)

《k8s上运行的mysql、mariadb数据库的备份记录(支持x86和arm两种架构)》本文记录在K8s上运行的MySQL/MariaDB备份方案,通过工具容器执行mysqldump,结合定时任务实... 目录前言一、获取需要备份的数据库的信息二、备份步骤1.准备工作(X86)1.准备工作(arm)2.手