Provider
// Provider把store放到context里,所有的子元素可以直接取到store
import React from 'react'
import PropTypes from 'prop-types'
import {bindActionCreators} from './utils.js'
export const connect = (mapStateToProps=state=>state,mapDispatchToProps={})=>(WrapComponent)=>{
return class ConnectComponent extends React.Component{
static contextTypes = {
store:PropTypes.object
}
constructor(props, context){
super(props, context)
this.state = {
props:{}
}
}
componentDidMount(){
const {store} = this.context
store.subscribe(()=>this.update())
this.update()
}
update(){
const {store} = this.context
const stateProps = mapStateToProps(store.getState())
const dispatchProps = bindActionCreators(mapDispatchToProps, store.dispatch)
this.setState({
props:{
...this.state.props,
...stateProps,
...dispatchProps
}
})
}
render(){
return <WrapComponent {...this.state.props}></WrapComponent>
}
}
}
export class Provider extends React.Component{
static childContextTypes = {
store: PropTypes.object
}
getChildContext(){
return {store:this.store}
}
constructor(props, context){
super(props, context)
this.store = props.store
}
render(){
return this.props.children
}
}
utils.js
export function createStore(reducer, enhancer){
if (enhancer) {
return enhancer(createStore)(reducer)
}
let currentState = {}
let currentListeners = []
function getState(){
return currentState
}
function subscribe(listener){
currentListeners.push(listener)
}
function dispatch(action){
currentState = reducer(currentState, action)
currentListeners.forEach(v=>v())
return action
}
dispatch({type:'@IMOOC/WONIU-REDUX'})
return { getState, subscribe, dispatch}
}
// 自定义applyMiddleware函数
export function applyMiddleware(...middlewares){
return createStore=>(...args)=>{
const store = createStore(...args)
let dispatch = store.dispatch
const midApi = {
getState:store.getState,
dispatch:(...args)=>dispatch(...args)
}
const middlewareChain = middlewares.map(middleware=>middleware(midApi))
dispatch = compose(...middlewareChain)(store.dispatch)
return {
...store,
dispatch
}
}
}
// 自定义compose函数
export function compose(...funcs){
if (funcs.length==0) {
return arg=>arg
}
if (funcs.length==1) {
return funcs[0]
}
return funcs.reduce((ret,item)=> (...args)=>ret(item(...args)))
}
function bindActionCreator(creator, dispatch){
return (...args) => dispatch(creator(...args))
}
export function bindActionCreators(creators,dispatch){
return Object.keys(creators).reduce((ret,item)=>{
ret[item] = bindActionCreator(creators[item],dispatch)
return ret
},{})
}