Redux核心API的实现
主要实现下 redux中核心API
- createStore
- applyMiddleware
- 以及异步中间件thunk
手写 createStore
- 环境搭建
- store 中将 import 的 redux 改为 ‘./ZRedux.js’
- 实现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;