Redux中间件
2. redux [#](#t12. redux)
2.1 index.js [#](#t22.1 index.js)
import createStore from './createStore';
import combineReducers from './combineReducers';
import bindActionCreators from './bindActionCreators';
import compose from './compose';
import applyMiddleware from './applyMiddleware';
export {
createStore,
combineReducers,
bindActionCreators,
compose,
applyMiddleware
}
2.2 createStore.js [#](#t32.2 createStore.js)
export default function (reducer, preloadedState,enhancer) {
if (typeof enhancer !== 'undefined') {
return enhancer(createStore)(reducer, preloadedState)
}
let state = preloadedState;
let listeners = [];
function getState() {
// return state;
return JSON.parse(JSON.stringify(state));
}
//派发分发的意思
//action 动作 描述一下你想干什么,动作是一个普通的JS对象,只有一个属性是必须的。type,其它属性随意
function dispatch(action) {
//接收新的动作后,通过 才状态 和新动作计算出新状态
state = reducer(state, action);
//然后通过所有的监听函数执行
listeners.forEach(listener => listener());
}
//派发了一个动作获取初始值,其实在redux内部是派发一个INIT: '@@redux/INIT'动作
dispatch({ type: '@@redux/INIT' });
//订阅,供外界订阅本仓库中状态的变化 ,如果状态 变化 了会执行订阅的逻辑
function subscribe(listener) {
listeners.push(listener);
//返回一个取消订阅函数
return function () {
listeners = listeners.filter(item => item != listener)
}
}
return {
getState, dispatch, subscribe
}
}
2.3 combineReducers.js [#](#t42.3 combineReducers.js)
export default reducers => (state = {}, action) => Object.keys(reducers).reduce((currentState, key) => {
currentState[key] = reducers[key](state[key], action);
return currentState;
}, {});
2.4 bindActionCreators.js [#](#t52.4 bindActionCreators.js)
export default function bindActionCreators(actions,dispatch){
let newActions = {};
for(let attr in actions){
newActions[attr] = function(){
dispatch(actions[attr].apply(null,arguments));
}
}
return newActions;
}
2.5 compose.js [#](#t62.5 compose.js)
export default function (...funcs){
return funcs.reduce((a,b)=>(...args)=>a(b(...args)));
}
2.6 applyMiddleware.js [#](#t72.6 applyMiddleware.js)
import compose from './compose';
export default function(...middlewares){
return function(createStore){
return function(reducer){
let store = createStore(reducer);
let dispatch;
middlewares = middlewares.map(middleware=>middleware({
getState:store.getState,
dispatch:action=>dispatch(action)
}));
dispatch = compose(...middlewares)(store.dispatch);
return {...store,dispatch};
}
}
}
3. react-redux [#](#t83. react-redux)
index.js
import connect from './connect';
import Provider from './Provider';
export {
connect,
Provider
}
3.1 connect.js [#](#t93.1 connect.js)
import React,{Component} from 'react';
import {bindActionCreators} from '../redux';
import propTypes from 'prop-types';
export default function(mapStateToProps,mapDispatchToProps){
return function(WrapedComponent){
class ProxyComponent extends Component{
static contextTypes = {
store:propTypes.object
}
constructor(props,context){
super(props,context);
this.store = context.store;
this.state = mapStateToProps(this.store.getState());
}
componentWillMount(){
this.unsubscribe = this.store.subscribe(()=>{
this.setState(mapStateToProps(this.store.getState()));
});
}
componentWillUnmount(){
this.unsubscribe();
}
render(){
let actions= {};
if(typeof mapDispatchToProps == 'function'){
actions = mapDispatchToProps(this.store.disaptch);
}else if(typeof mapDispatchToProps == 'object'){
actions = bindActionCreators(mapDispatchToProps,this.store.dispatch);
}
return <WrapedComponent {...this.state} {...actions}/>
}
}
return ProxyComponent;
}
}
3.2 Provider.js [#](#t103.2 Provider.js)
//用来通过上下文对象向下层组件传递数据 store
import React,{Component} from 'react';
import propTypes from 'prop-types';
export default class Provider extends Component{
static childContextTypes = {
store:propTypes.object.isRequired
}
getChildContext(){
return {store:this.props.store};
}
render(){
return this.props.children;
}
}
4. 中间件 [#](#t114. 中间件)
4.1 自己实现日志中间件 [#](#t124.1 自己实现日志中间件)
我们改写了,dispatch方法实现了在更改状态时打印前后的状态,但是这种方案并不好。所以我们可以采用中间的方式。
let store = createStore(reducer);
let dispatch = store.dispatch;
store.dispatch = function (action) {
console.log(store.getState().number);
dispatch(action);
console.log(store.getState().number)
};
export default store;
4.2 实现logger中间件 [#](#t134.2 实现logger中间件)
中间件就是一个函数,对store.dispatch方法进行了改造,在发出 Action 和执行 Reducer 这两步之间,添加了其他功能
let logger = store => dispatch => action=>{
console.log(store.getState().number);
dispatch(action);
console.log(store.getState().number)
};
let applyMiddleWare = middleware => createStore => reducer =>{
let store = createStore(reducer);
let middle = middleware(store);
let dispatch = middle(store.dispatch);
return { //将中间返回的dispatch方法覆盖掉原有store中的dispatch
...store,
dispatch
}
};
export default applyMiddleWare(logger)(createStore)(reducer);
#
5.counter5.1 Counter.js [#](#t155.1 Counter.js)
import React, { Component } from 'react';
import store from '../store';
import actions from '../store/actions/counter';
import {connect} from '../react-redux';
class Counter extends Component {
constructor(props){
super(props);
}
render() {
return (
<div>
<p>{this.props.number}</p>
<button onClick={this.props.increment} >+</button>
<button onClick={this.props.thunkIncrement} >thunk+</button>
<button onClick={this.props.promiseIncrement} >promise+</button>
<button onClick={this.props.payloadIncrement} >payload+</button>
</div>
)
}
}
export default connect(
state=>state,
actions
)(Counter);
5.2 actions.js [#](#t165.2 actions.js)
import * as types from '../action-types';
//actionCreator 创建action的函数
export default {
increment(){
return {type:types.INCREMENT,payload:1}
},
thunkIncrement(){
return function(dispatch,getState){
setTimeout(function(){
dispatch({type:types.INCREMENT,payload:1});
},1000);
}
},
promiseIncrement(){
return new Promise(function(resolve){
setTimeout(function(){
resolve({type:types.INCREMENT,payload:1});
},1000);
});
},
payloadIncrement(){
return {
type:types.INCREMENT,
payload:new Promise(function(resolve,reject){
setTimeout(function(){
if(Math.random()>.5){
resolve(1);
}else{
reject(-1);
}
},1000);
})
}
}
}
5.3 reducers.js [#](#t175.3 reducers.js)
import * as types from '../action-types';
export default function(state={number:0},action){
switch(action.type){
case types.INCREMENT:
return {number:state.number + (action.payload)};
default:
return state;
}
}
action-types.js
export const INCREMENT = 'INCREMENT';
5.4 compose.js [#](#t185.4 compose.js)
function add1(str){
return '1'+str;
}
function add2(str){
return '2'+str;
}
function add3(str){
return '3'+str;
}
function compose1(...fns){
return function(...args){
let last = fns.pop();
return fns.reduceRight(function(val,fn){
return fn(val);
},last(...args))
}
}
function compose2(...fns){
return function(...args){
return fns.reduce((a,b)=>a(b(...args)));
}
}
function compose3(...funcs){
return funcs.reduce((a,b)=>(...args)=>a(b(...args)));
}
let result = compose3(add3,add2,add1)('zxmf');
console.log(result);
5.5 applyMiddleware [#](#t195.5 applyMiddleware)
let applyMiddleware = function(middleware){
return function(createStore){
return function(reducer){
let store = createStore(reducer);
middleware = middleware(store);
let dispatch = middleware(store.dispatch);
return {...store,dispatch}
}
}
}
5.6 logger [#](#t205.6 logger)
let logger = function(store){
return function(next){
return function(action){
console.log(store.getState());
next(action);
console.log(store.getState());
}
}
}
5.7 thunk [#](#t215.7 thunk)
let thunk = function({getState,dispatch}){
return function(next){
return function(action){
if(typeof action == 'function'){
action(dispatch,getState);
}else{
next(action);
}
}
}
}
5.8 promise [#](#t225.8 promise)
let promise = function({getState,dispatch}){
return function(next){
return function(action){
if(action.then){
action.then(dispatch);
}else if(action.payload && action.payload.then){
action.payload.then(payload=>dispatch({...action,payload}),payload=>dispatch({...action,payload}));
}else{
next(action);
}
}
}
}
5.9 join.js [#](#t235.9 join.js)
import {createStore} from 'redux';
import reducers from './reducers';
let logger = function(store){
return function(next){
return function(action){
console.log(store.getState());
next(action);
console.log(store.getState());
}
}
}
let thunk = function({getState,dispatch}){
return function(next){
return function(action){
if(typeof action == 'function'){
action(dispatch,getState);
}else{
next(action);
}
}
}
}
let promise = function({getState,dispatch}){
return function(next){
return function(action){
if(action.then){
action.then(dispatch);
}else if(action.payload && action.payload.then){
action.payload.then(payload=>dispatch({...action,payload}),payload=>dispatch({...action,payload}));
}else{
next(action);
}
}
}
}
function compose(...funcs){
return funcs.reduce((a,b)=>(...args)=>a(b(...args)));
}
let applyMiddleware = function(...middlewares){
return function(createStore){
return function(reducer){
let store = createStore(reducer);
let dispatch;
middlewares = middlewares.map(middleware=>middleware({
getState:store.getState,
dispatch:action=>dispatch(action)
}));
dispatch = compose(...middlewares)(store.dispatch);
return {...store,dispatch};
}
}
}
let store = applyMiddleware(thunk,promise,logger)(createStore)(reducers);
export default store;
Gitalking ...
Be the first guy leaving a comment!