redux源码以及中间件剖析

redux相信使用react进行开发项目的过程中是必然会使用到的第三方库,并且他相比于vuex来说有很大的独立性,他并不依赖于react语言包。你对于redux的源码以及中间件有深入理解吗?

redux工作流

redux使用以及中间件的应用

redux只是能支持同步内容的执行,并且只能使用对象的形式作为action传到reducer中作为参数,如果要用函数作为参数传递的时候,redux就会报错,因此需要借助于一些中间件进行支持!

## 创建store,src/store/index.js
import {createStore} from "redux";
function countReducer(state = 0, action) {
   switch (action.type) {
   case "ADD":
   return state + 1;
   case "MINUS":
   return state - 1;
   default:
   return state;
    }
}
const store = createStore(countReducer);
export default store;

## 应⽤中间件
import { createStore, applyMiddleware } from "redux";
import logger from "redux-logger";
import thunk from "redux-thunk";
import counterReducer from './counterReducer'
const store = createStore(counterReducer, applyMiddleware(thunk, logger));

import { createStore, applyMiddleware } from "redux";
代码我们可以看出redux会抛出两个方法:一个是createStore,另一个是应用中间件:applyMiddleware
const store = createStore(counterReducer, applyMiddleware(thunk, logger));
从代码可以看出createStore是一个函数,并且reducer以及应用中间件函数式作为参数进行执行


redux在组件中的使用

import React, {Component} from "react";
import store from "../store/";

export default class ReduxPage extends Component {
componentDidMount() {
 this.unsubscribe = store.subscribe(() => {
   this.forceUpdate();
 });
}

componentWillUnmount() {
 if (this.unsubscribe) {
   this.unsubscribe();
 }
}

add = () => {
 store.dispatch({type: "ADD"});
};

asyAdd = () => {
 store.dispatch((dispatch, getState) => {
   setTimeout(() => {
     dispatch({type: "ADD"});
   }, 1000);
 });
};
promiseMinus = () => {
 store.dispatch(
   Promise.resolve({
     type: "MINUS",
     payload: 100
   })
 );
};
render() {
 return (
   <div>
     <h3>ReduxPage</h3>
     <p>{store.getState()}</p>
     <button onClick={this.add}>add</button>
     <button onClick={this.asyAdd}>asyAdd</button>
     <button onClick={this.promiseMinus}>promiseMinus</button>
   </div>
 );
}
}

从在组件的使用中可以看出redux是有dispatch方法用来派发执行时间,getState是用来获取最新的state状态,subscribe是用来进行强制更新的回调。

综上所述,我们对于源码有以下几点的实现:

1、createStore函数的实现,并且抛出了getState、dispatch、subscribe 函数
2、applyMiddleware函数的实现,核⼼任务是实现函数序列执⾏。

源码

1、createStore函数 主要原理是使用了发布订阅模式

export default function createStore(reducer, enhancer) {
  // enhancer是应用中间件函数
  if (enhancer) {
    // enhancer需要对于dispatch进行加强
    return enhancer(createStore)(reducer);
  }
  // 存储当前状态
  let currentState;
  // 存储订阅时间的强制更新函数
  let currentListeners = [];
  // 获取store state获取
  function getState() {
    return currentState;
  }

  // 修改状态
  function dispatch(action) {
    // 更新state状态并进行组件的更新
    currentState = reducer(currentState, action);
    currentListeners.forEach(listener => listener());
  }
  function subscribe(listener) {
   //收集组件更新方法
    currentListeners.push(listener);
    return () => {
      // 简单置空,大家可以自己实现过滤
      currentListeners = [];
    };
  }
  // 派发一个唯一的函数名,以获取最初始化的state状态
  dispatch({type: "KKKKREDUX/OOOOOO"});

  return {
    getState,
    dispatch,
    subscribe
  };
}

2、applaymiddlware的实现

export default function applyMiddleware(...middlewares) {
  return createStore => reducer => {
    let store = createStore(reducer);
    // 这是原版的dispatch,这个dispatch只能接受plain object,不能处理异步、promise
    let dispatch = store.dispatch;
    const midApi = {
      getState: store.getState,
      dispatch: (action, ...args) => dispatch(action, ...args)
    };

    const middlewaresChain = middlewares.map(middleware => middleware(midApi));

    dispatch = compose(...middlewaresChain)(store.dispatch);

    return {
      ...store,
      // 加强版的dispatch
      dispatch
    };
  };
}
// 对于中间件的处理,使用的是组合函数即高阶函数
function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg;
  }
  if (funcs.length === 1) {
    return funcs[0];
  }
  return funcs.reduce((a, b) => (...args) => a(b(...args)));
}
原文链接:juejin.im

上一篇:JavaScript 数据类型及判断
下一篇:antd popover定位不准闪跳解决+自己实现popover库

相关推荐

  • 🚩Vue源码——组件是如何注册的

    最近参加了很多场面试,几乎每场面试中都会问到Vue源码方面的问题。在此开一个系列的专栏,来总结一下这方面的经验,如果觉得对您有帮助的,不妨点个赞支持一下呗。 前言 在上一篇 🚩Vue源码——组件...

    24 天前
  • 🚩Vue源码——组件如何渲染成最终的DOM

    最近参加了很多场面试,几乎每场面试中都会问到Vue源码方面的问题。在此开一个系列的专栏,来总结一下这方面的经验,如果觉得对您有帮助的,不妨点个赞支持一下呗。 前言 Vue有两个核心思想,一个是数据...

    1 个月前
  • 🚩Vue源码——如何监听数据变化

    最近参加了很多场面试,几乎每场面试中都会问到Vue源码方面的问题。在此开一个系列的专栏,来总结一下这方面的经验,如果觉得对您有帮助的,不妨点个赞支持一下呗。 前言 Vue 是用数据来驱动来生成视图...

    6 天前
  • 🔥手写大厂前端知识点源码系列(上)

    如今前端攻城狮的要求越来越高,会使用常见的API已经不能满足现如今前端日益快速发展的脚步。现在大厂基本都会要求面试者手写前端常见API的原理,以此来证明你对该知识点的理解程度。

    7 个月前
  • 🔥前端面试大厂手写源码系列(上)

    如今前端攻城狮的要求越来越高,会使用常见的API已经不能满足现如今前端日益快速发展的脚步。现在大厂基本都会要求面试者手写前端常见API的原理,以此来证明你对该知识点的理解程度。

    7 个月前
  • (源码分析)为什么 Vue 中 template 有且只能一个 root ?

    引言 今年,疫情并没有影响到各种面经的正常出现,可谓是络绎不绝(学不动...)。然后,在前段时间也看到一个这样的关于 Vue 的问题,为什么每个组件 template 中有且只能一个 root? 可能...

    6 个月前
  • 面试还问redux?那我从头手撸源码吧(中间件篇)

    昨天的文章手写了一版redux的核心源码,redux库除了数据的状态管理还有一块重要的内容那就是中间件,今天我还是尝试将此部分源码完成。 中间件 react中管理数据的流程是单向的,就是说,从派发动作...

    2 年前
  • 防抖与节流(源码学习)

    最近自己撸了一个轮播图,在点击切换的时候,为了寻求更好的用户体验,引入了节流,在此记录对源码的学习过程 源码来源:underscore 防抖 函数防抖(debounce) 使用场景:现在我们需要做一个...

    2 年前
  • 阅读redux源码_compose

    先上源码: // 将(fun1,fun2,fun3)转换成fun1(fun2(fun3())) export default function compose(...funcs) { if (fu...

    2 年前
  • 阅读 is-generator-function 源码

    Function.prototype.toString 从正则表达式 /^\s*(?:function)?\*/ 可知 1: GeneratorFunction 不管书写是 function* 还是...

    2 年前

官方社区

扫码加入 JavaScript 社区