redux異步的實現方式 | redux(三)

redux基礎知識 | redux(二)javascript

在上一篇文章中,咱們經實現了一個基本的redux,那若是咱們想在redux中實現異步的操做怎麼辦?java

好比下面的操做react

pages/ReduxPage.jsgit

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()
        }
    }
    asyAdd = () => {
        store.dispatch((dispatch,getState) => {
            setTimeout(() => {
                dispatch({type: 'ADD', payload: 1})
            }, 1000)
        })
    }
    promiseAdd = () => {
        store.dispatch(Promise.resolve({type: "MINUS", payload: 1}));
    }
    render() {
        return(
            <div> <h3>Reduxpage</h3> <p>{count}</p> <button onClick={this.asyAdd}>異步+</button> <button onClick={this.promiseAdd}>promise-</button> </div>
        )
    }
}
複製代碼

上面的操做咱們有兩個異步的操做,分別是是setTimeout和Promise。因爲咱們的action觸發了之後,就會立馬去reducer裏面執行state的更新,因此咱們想要實現異步的操做,就必須在dispatch的時候,去作一些操做。github

在store裏面,有個方法叫作applyMiddleware(),它能夠接收一些參數,二接受的這些參數,就是咱們處理異步的中間件,咱們看一下怎麼使用的。redux

import { createStore, applyMiddleware } from 'redux';
import logger from 'react-logger';
import thunk from 'react-thunk';
import rdPromise from 'react-promise'

const countReducer = (state = 0, action) => {
    const {type, payload} = action
    switch(type) {
        case 'ADD':
            return state + payload;
        case 'MINUS':
            return state - payload;
        default:
            return state
    }
}

const store = createStore(
    countReducer,
    applyMiddleware(thunk, logger, rdPromise)
)
export default store;
複製代碼

applyMiddleware()接收了三個參數:promise

  • thunk,處理setTimeout這種異步
  • logger,打印state日誌
  • rdPromise,處理promise異步

這樣子,咱們上面的異步操做按鈕就能夠正常的工做了,下面讓咱們看看源碼如何實現的。bash

Jreact/createStore.jsapp

export default function createStore(reducer, enhancer) {
    if(enhancer) {
        return enhancer(createStore)(reducer)
    }
}
複製代碼

在createStore裏面,咱們須要判斷一下createStore的第二個參數,也就是applyMiddleware,有的話,就把createStore和reducer傳給它,咱們須要在內部去使用這兩個參數。異步

Jreact/applyMiddleware.js

export default function applyMiddleware(...middlewares) {
    return createStore => reducer => {
        const store = createStore(reducer)
        let dispatch = store.dispatch

        const midApi = {
            getState: store.getState,
            dispatch: (action, ...args) => dispatch(action, ...args)
        }

        const middlewareChain = middlewares.map(md => md(midApi))
        dispatch = compose(...middlewareChain)(store.dispatch);

        return {
            ...store,
            dispatch
        }
    }
}

// 聚合函數
function compose(...funcs) {
    if (funcs.length === 0) {
      return arg => arg;
    }
    if (funcs.length === 1) {
      return funcs[0];
    }
    return funcs.reduce((a, b) => (...args) => {
      return a(b(...args));
    });
  }
複製代碼

applyMiddleware(...middlewares)就是接收的thunk, logger, rdPromise這幾個參數,而後在裏面對dispatch作了增強。咱們對middlewares作了便利,也就是thunk, logger, rdPromise,他們會接收getState和dispatch,而後在每一箇中間件的內部獨立處理本身的邏輯,處理完成之後會造成一個middlewareChain,使用一個聚合函數compose,把middlewareChain裏面的函數聚合一個,增強了dispatch,最後返回出去,這樣就能夠在dispatch的時候,作一些操做了。

下面是三個中間件的實現

Jreact/thunk.js

export default function thunk({dispatch, getState}) {
    return next => action => {
        if(typeof action === 'function') {
            return action(dispatch, getState)
        }
        return next(action)
    }
}
複製代碼

Jreact/logger.js

export default function logger({getState}) {
    return next => action => {
        console.log('prevState', getState());
        const newState = next(action)
        console.log('nextState', getState());
        return newState
    }
}
複製代碼

Jreact/rdPromise.js

import { isFSA } from 'flux-standard-action';
import isPromise from 'is-promise';

export default function rdPromise({dispatch}) {
    return next => action => {
        if(!isFSA(action)) {
            return isPromise(action) ? action.then(dispatch) : next(action)
        }
        return next(action)
    }
}
複製代碼

這是三個函數,經過聚合函數依次執行他們,就能夠了。

至此,redux的源碼就講的差很少了

參考連接

相關文章
相關標籤/搜索