手写Redux

Redux核心API的实现

主要实现下 redux中核心API

  • createStore
  • applyMiddleware
  • 以及异步中间件thunk

手写 createStore

  1. 环境搭建
  • store 中将 import 的 redux 改为 ‘./ZRedux.js’
  1. 实现createStore
    该函数主要是接受两个参数,(reducer, enhancer) 返回一个对象,包括常用的getState、dispatch、subscribe
export const createStore = (reducer,enhancer)=>{
     // enhancer是applyMiddleware(...middleware)的返回函数
    if(enhancer){
        // 这里其实是对dispatch做了增强后再return ,让我们可以处理一些额外的事情
       return enhancer(createStore)(reducer)
    }
    
    // 当前state
    let currentState = undefined
    let subscribeStack = []
    // getState 直接返回当前state
    function getState(){
        return currentState
    }
    // dispatch 传入一个action,执行reducer函数得到最新状态,通知订阅 
    function dispatch(action){
        currentState = reducer(currentState,action)
        subscribeStack.map(cb => cb())
        return action 
    }
    // 推入订阅数组中
    function subscribe(cb){
        subscribeStack.push(cb)
    }
    dispatch({type:'SOME_TYPE'})
    return {
        getState,
        dispatch,
        subscribe
    }
}

关于enhancer的实现,可以结合下面applyMiddleware更好的理解。

手写 applyMiddleware

再来看第二个参数,我们在使用的时候一般是这样

const store = createStore(counterReducer, applyMiddleware(logger, thunk))

所以先弄清楚applyMiddleware里面做了什么?

在写之前,我们先回顾一下Array.prototype.reduce的用法,比如我们让一些函数能够顺序的执行,类似这样

const f1 = () => console.log('fn1')

const f2 = () => console.log('fn2')

const f3 = () => console.log('fn3')

...
甚至更多

// 使用reduce可以快速的实现
实现一个compose函数

const compose = (...funcs)=>{
    let len = funcs.length
    if(len === 0){
        return arg=>arg
    }else if(len === 1){
        return funcs[0]
    }else{
        return funcs.reduce((a,b)=>(...args)=>b(a(...args)))
    }
}
compose(f1,f2,f3)('xxxx') // xxxx fn2 fn3

applyMiddleware 中其实也是对一组中间件的compose, 它通过将store的API传入中间件中,然后顺序调用每个中间件来增强原始的dispatch,最后连同其他API一并返回。

export const applyMiddleware = (...middlewares) =>{
    return createStore => (...args) =>{
        // 1. 拿到store
        const store = createStore(...args)
        
        let dispatch = store.dispatch
        const mapStore={
            getState:store.getState,
            dispatch: (...args) => dispatch(...args)
        }
        // 2. 处理中间件,将store中的方法当做参数传入,让中间件能够访问状态和派发动作
        // 这里可以参照看redux-thunk的实现
        const middlewareMaps = middlewares.map(middleware => middleware(mapStore))
        // 3. 顺序执行中间件
        dispatch = compose(...middlewareMaps)(dispatch)
        return {
            ...store,
            dispatch
        }
    }
}

function compose(...fns){
    if(fns.length === 0){
        return args=>args
    }else if(fns.length === 1){
        return fns[0]
    }else{
        return fns.reduce((a,b)=>(...args)=>a(b(...args)))
    }

}

手写 thunk 实现

export function thunk({getState}){
    // 接受dispatch,返回一个增强的dispatch
    return dispatch => action=>{
        // 新的dispatch除了可以处理普通对象的action,还可以处理异步fn
        if(typeof action === 'function'){
            return action(dispatch, getState)
        }else{
            return dispatch(action)
        }
    }
}

现在来写一个测试页面

store文件

import { counterReducer } from '../reducer/counterReducer'

// 引入自己的实现代码
import { createStore, applyMiddleware,thunk } from '../ZRedux'

const store = createStore(counterReducer, applyMiddleware(thunk))

export default store

page

import React, { Component } from 'react'
import store from '../store/myReduxStore'

class MyReduxPage extends Component {
    state = {}
    // 手动更新
    componentDidMount(){
        store.subscribe(()=>{
            this.forceUpdate()
        })
    }
    // 异步action
    handlerAsyncAdd= ()=>{
        // 使用了增强后的dispatch,可以处理函数形式的action
        store.dispatch(dispatch=>{
            setTimeout(()=>{
                dispatch({type:'ADD'})
            },1000)
        })
    }

    render() {
        return (
            <div>
                <p>{store.getState()}</p>
                <button onClick={this.handlerAsyncAdd}>异步加</button>
            </div>
        );
    }
}

export default MyReduxPage;

下一篇手写React-Redux

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值