// 聚合函数 用于applymiddleware
function compose(...funs) {
const len = funs.length;
if(len === 0) return a => a
if(len === 1) return funs[0]
return funs.reduce((left, right) => {
return (...args) => right(left(...args))
})
}
// store 原理
// 返回一个具有 createStore dispatch subscribe方法的对象
// redux 暴露的createStore 方法
const createStore = (reducer, enhancer) => {
// enhancer 是一个增强器 比如中间件 applymiddleware
if(enhancer) return enhancer(createStore)(reducer)
let cur = undefined;
let curlist = []; //存放监听函数
function getState() {
return cur
}
function dispatch(action) {
cur = reducer(cur, action)
curlist.map(cl => cl())
}
function subscribe(listener) {
curlist.push(listener)
}
dispatch({type:'1111'}) ;//默认状态下 要先触发一次
return {
getState, dispatch, subscribe
}
}
// redux 暴露的 applymiddleware方法
// createStore(reducer, applymiddleware(logger, thunk))
// 起初list 是按照从做向右的方向执行
// 最后的执行结果是右向左执行
const applymiddleware = (...list) => {
// 接受createStore作为参数 返回一个函数
return createStore => (...args) => {
let store = createStore(...args);
const midApi = {
getState: store.getState,
dispatch: store.dispatch
}
const chain = list.map( mw => mw(midApi))
// mw(midApi) 返回一个函数
const dispatch = compose(...chain)(store.dispatch)
return {
...store, dispatch
}
}
}
const logger = () => {
return dispatch => action => {
return dispatch(action)
}
}
const thunk = () => {
return dispatch =>action => {
if(typeof action === 'function') action()
dispatch(action)
}
}
// react-redux 提供provider connect方法
// provider 基于context原理
// connect 将dispatch state映射到props 并订阅变化用于实时刷新
import { connect } from "react-redux";
import { useContext, useState, useEffect } from "react";
const Context = React.createContext();
export const Provider = props => {
return <Context.Provider value={props.store}>
{props.children}
</Context.Provider>
}
export const connect = (
mapStatetoProps = state => state,
mapDispatchtoProps = {} // 爱react-redux 中 这个既可以是对象 可以是一个函数
) => {
return Cmp => {
return () => {
const store = useContext(Context)
const getProps = () => {
const stateProps = mapStatetoProps(store.getState())
const dispatchProps = bindActionCreators(mapDispatchtoProps, store.dispatch)
}
return {
...stateProps, ...dispatchProps
}
const [props, setProps] = useState({...getProps()})
useEffect(() => {
store.subsribe(() => {
setProps({...props, ...getProps()})
})
return store.unsubscribe()
}, [])
return <Cmp {...props}/>
}
}
}
function bindActionCreators(creators, dispatch) {
return Object.keys(creators).reduceRight((ret, item) => {
ret[item] = bindActionCreator(creator[item], dispatch)
return ret
})
}
function bindActionCreator(creators, dispatch) {
return (...args)=> dispatch(creators(...args))
}