博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Redux源码分析
阅读量:6413 次
发布时间:2019-06-23

本文共 5836 字,大约阅读时间需要 19 分钟。

import './index.css'import React from 'react'import ReactDOM from 'react-dom'import App from './App/App'import { createStore } from 'redux'const store = createStore((state = { count: 1 }, action) => {    switch (action.type) {        case 'ADD':            state.count += action.value            break        case 'MINUS':            state.count -= action.value            break    }    return state})function createAction(type, value) {    return () => {        store.dispatch({            type,            value        })    }}function render() {    ReactDOM.render(        
, document.getElementById('root') )}render()store.subscribe(render)复制代码

以上是使用Redux的一个最简单的例子。涵盖了redux的基本使用方式,用户点击按钮 --> dispatch(action) --> 更新store --> 触发监听函数render,重绘。

文件目录

  • applyMiddleware.js // Redux的插件机制实现,可以重点学习一下
  • bindActionCreators.js // 将ActionCreator和dispatch绑定的工具
  • combineReducers.js // 将store分层的工具
  • compose.js // 将数个函数合并嵌套执行
  • createStore.js // 核心,生成store
  • index.js // 入口

combineReducers

const store = createStore(combineReducers({
PageA: PageAReducer, PageB: PageBReducer}))复制代码

因为createStore的接收的是一个函数,当dispatch发生时,它就会被执行,将当前的store和被触发的action作为参数,传入这个函数。所以combineReducers的主要任务就是:遍历一个combinedReducers对象,将每个子reducer依次执行,并将执行结果赋予其所对应的key,最后返回一个总的newStore。有了以上的基础,我们来看源码实现:

export default function combineReducers(reducers) {  const reducerKeys = Object.keys(reducers)  const finalReducers = {}  for (let i = 0; i < reducerKeys.length; i++) {    const key = reducerKeys[i]    // 将每一个子reducer,保存到finalReducer对象中    if (typeof reducers[key] === 'function') {      finalReducers[key] = reducers[key]    }  }  const finalReducerKeys = Object.keys(finalReducers)  return function combination(state = {}, action) {    let hasChanged = false    const nextState = {}    for (let i = 0; i < finalReducerKeys.length; i++) {      const key = finalReducerKeys[i]      // 取出一个子reducer      const reducer = finalReducers[key]      // 取得这个key对应的旧的值      const previousStateForKey = state[key]      // 核心操作,将旧的state和action传入这个reducer,得到新的state      const nextStateForKey = reducer(previousStateForKey, action)            if (typeof nextStateForKey === 'undefined') {        const errorMessage = getUndefinedStateErrorMessage(key, action)        throw new Error(errorMessage)      }      nextState[key] = nextStateForKey      hasChanged = hasChanged || nextStateForKey !== previousStateForKey    }    return hasChanged ? nextState : state  }}复制代码

applyMiddleware

createStore(reducers, applyMiddleware(reduxLogger, reduxPromise, reduxThunk))复制代码

这个插件机制是Redux一个很重要的功能,使得我们可以很方便的对action做各种各样的操作。比如日志打印,异步数据获取等等,只要添加一个middleware,就可以实现。这个类似于Express或者Koa中的中间件机制。我们来看一下他们是如何实现的

export default function applyMiddleware(...middlewares) {  return createStore => (...args) => {    // 这里通过将createStore方法和参数传入的方式,得到store    // 为什么不直接将store传入呢?因为,我们查看createStore的代码,可以发现    // return enhancer(createStore)(reducer, preloadedState)    // 这里的 enhancer其实就是当前的applyMiddeware,通过这种方式,可以保证window.store是由applyMiddleware最后return出去的    // 这个对我们以后写组件有借鉴意义,比如    // 我们有一个 ComponentA:  const compA = new Component(args);    // 现在我们想强化一下CompoentA的功能,通过传入组件B的方式,那么, const enhancedCompA = new ComponentA(args, B)    // 这时候,如果B需要ComponentA原有的结果,那么就可以使用这种方式,最后返回的结果一定是经过B处理过的    const store = createStore(...args)        let dispatch = () => {}        let chain = []    const middlewareAPI = {      getState: store.getState,      dispatch: (...args) => dispatch(...args)    }        // 将getState和dispatch,作为参数传给每一个middleware    chain = middlewares.map(middleware => middleware(middlewareAPI))        /**     这个compose的作用就是: compose(a,b,c) ===> (...args) => a(b(c(...args)))        假设有[a,b,c]三个middleware,他们都长这样:        ({ dispatch, getState }) => next => action => {        // 对action的操作 blablabla                return next(action);    };        那么,c会最先接收到一个参数,就是store.dispatch,作为它的next。然后c使用闭包将这个next存起来,把自己作为下一个middleware b的next参数传入。这样,就将所有的middleware串起来了。    最后,如果用户dispatch一个action,那么执行顺序会是: c --> b --> a    **/        dispatch = compose(...chain)(store.dispatch)    return {      ...store,      dispatch    }  }}复制代码

createStore

createStore主要会返回三个东西:

  • getState
  • subscribe
  • dispatch

getState

很简单,返回当前的store

function getState() {    // 这里有个锁的机制,保证当另一个action在dispatch时,getState无法生效    if (isDispatching) {      throw new Error(        'You may not call store.getState() while the reducer is executing. ' +          'The reducer has already received the state as an argument. ' +          'Pass it down from the top reducer instead of reading it from the store.'      )    }    return currentState  }复制代码

subscribe

注册监听函数

function subscribe(listener) {    if (isDispatching) {      throw new Error(...)    }    let isSubscribed = true    // 这里Redux维护了两个Listener List:    // currentListeners    // nextListeners    // 因为currentListeners和nextListeners是独立的,就可以保证当currentListeners还在执行的时候,调用subscribe或unsubscribe是不会影响到原先原先注册的listeners的。    // 只有当下一次dispatch前,nextListeners又被同步给了currentListeners,之前的注册注销才会生效         ensureCanMutateNextListeners()    nextListeners.push(listener)    return function unsubscribe() {      if (!isSubscribed) {        return      }      if (isDispatching) {        throw new Error(...)      }      isSubscribed = false      ensureCanMutateNextListeners()      const index = nextListeners.indexOf(listener)      nextListeners.splice(index, 1)    }  }复制代码

dispatch

redux中最常用的一个方法了

function dispatch(action) {    if (isDispatching) {      throw new Error('Reducers may not dispatch actions.');    }    try {      isDispatching = true;      // 使用绑定的reducer,计算出新的store      currentState = currentReducer(currentState, action);    } finally {      isDispatching = false;    }    // 触发所有绑定的监听器    var listeners = currentListeners = nextListeners;    for (var i = 0; i < listeners.length; i++) {      var listener = listeners[i];      listener();    }    return action;  }复制代码

转载地址:http://vgdra.baihongyu.com/

你可能感兴趣的文章
java线程同步原理(lock,synchronized)
查看>>
MyEclipse中使用Hql编辑器找不到Hibernate.cfg.xml文件解决方法
查看>>
yRadio以及其它
查看>>
第四节 对象和类
查看>>
闪迪(SanDisk)U盘防伪查询(官方网站)
查看>>
Android onMeasure方法介绍
查看>>
无锁数据结构
查看>>
MySQL的变量查看和设置
查看>>
android onNewIntent
查看>>
XML特殊符号
查看>>
kaptcha可配置项
查看>>
JavaMail邮箱验证用户注册
查看>>
系统时间——ntpd
查看>>
反射实现AOP动态代理模式(Spring AOP实现原理)
查看>>
Spring MVC 4.x + fastjson 1.2.7,封装的List<?>参数
查看>>
js选中问题
查看>>
protobuf
查看>>
4.Java基础复习--Set
查看>>
七:Mysql的乐观锁与悲观锁机制
查看>>
CSS滤镜及渐变 (filter样式表属性)
查看>>