Redux

1、数据流

image

2、redux的实现

const createStore = (reducer) => {
    let state = {};
    let listeners = [];

    const getState = () => state;

    const dispatch = (action) => (reducer) => {
        state = reducer(state, action);
        listeners.forEach(fn => fn());
    }

    let subscribe = (listener) => {
        listeners.push(listener);
    }
    //初始的状态
    dispatch({type: '@@CHEN-REDUX});
    return { getState, dispatch, subscribe }
}

export {createStore} ;

3、context的使用

在生命周期方法中引用 Context
如果 contextTypes 在组件中定义,下列的生命周期方法将接受一个额外的参数, context 对象:

  • constructor(props, context)
  • componentWillReceiveProps(nextProps, nextContext)
  • shouldComponentUpdate(nextProps, nextState, nextContext)
  • componentWillUpdate(nextProps, nextState, nextContext)
  • componentDidUpdate(prevProps, prevState, prevContext)
  • function(props, context)

childContextTypes中声明类型要不不能用 getChildContext 中取

4、react-redux的实现

Provider 利用context属性可以让所有的子组件来取到store

// render(
//     <Provider store={store}>
//       <App />
//     </Provider>,
//     document.getElementById('root')
//   )

export class Provider extends React.Component {
    static childContextTypes = {
        store:PropTypes.object
    }
    constructor(props, context) {
        super(props, context);
        this.store = props.store;
    }

    getChildContext() {
        return {store: this.store}
    }

    render() {
        return this.props.children;
    }
}

connet 的实现

import React, {PropTypes} from 'react';

//高阶组件
//1.负责接收一个组件,把state里的数据放进去,返回一个组件
//2.数据变化的时候,能够通知组件

function bindActionCreator (creators, dispatch) {
    return (...args) => dispatch(creator(...args));
}

function bindActionCreators (creators, dispatch) {
    let bound = {};
    Object.keys(creators).forEach(v=>{
        let creator = creators[v]
        bound[v] = bindActionCreator(creator, dispatch)
    })
    return bound;
}

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;
            //把state传入mapStateToProps,然后返回自己需要的
            const stateProps = mapStateToProps(store.getState());
            //方法不能直接给,需要dispatch  直接执行addGun()是没有意义的。
            //需要addGun = store.dispatch(addGun 才有意义
            const dispatchProps = bindActionCreators(mapDispatchToProps, store.dispatch)
            this.setState({
                props: {
                    ...this.state.props,
                    ...stateProps,
                    ...dispatchProps
                }
                
            })
        }

        render() {
            return <WrapComponent {...this.state.props} />
        }
    }
};


5、中间件

中间件的理解

只有发送 Action 的这个步骤,即store.dispatch()方法,可以添加功能

举例来说,要添加日志功能,把 Action 和 State 打印出来,可以对store.dispatch进行如下改造。

let next = store.dispatch;
store.dispatch = function dispatchAndLog(action) {
  console.log('dispatching', action);
  next(action);
  console.log('next state', store.getState());
}

对store.dispatch进行了重定义,在发送 Action 前后添加了打印功能。这就是中间件的雏形。

中间件就是一个函数,对store.dispatch方法进行了改造,在发出 Action 和执行 Reducer 这两步之间,

中间件的使用
const store = createStore(
  reducer,
  initial_state,
  applyMiddleware(logger)
);
applyMiddlewares() 的实现单个
const createStore = (reducer, enhancer) => {
    if (enhancer) {
        return enhander(createStore)(reducer);
    }
    let state = {};
    let listeners = [];

    const getState = () => state;

    const dispatch = (action) => (reducer) => {
        state = reducer(state, action);
        listeners.forEach(fn => fn());
    }

    let subscribe = (listener) => {
        listeners.push(listener);
    }

    dispatch({});
    return { getState, dispatch, subscribe }
}

export function applyMiddleware (middleware) {
    return createStore=>(...args)=>{
        const store = createStore(...args);
        let dispatch = store.dispatch;

        const midApi = {
            getState: store.getState,
            dispatch: (...args) => dispatch(...args)
        }
        dispatch = middleware(midApi)(store.dispatch);
        return {
            ...store,
            dispatch
        }
    }
}

多个中间件

export default function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, preloadedState, enhancer) => {
    var store = createStore(reducer, preloadedState, enhancer);
    var dispatch = store.dispatch;
    var chain = [];

    var middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    };
    chain = middlewares.map(middleware => middleware(middlewareAPI));
    dispatch = compose(...chain)(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(...item)))
}

compost(f1, f2, f3)

f1(f2(f3()))
自己实现一个thunk 感觉就是处理异步的callback

const thunk = ({dispatch, getState})=>next=>action=> {
    if (typeof action == 'function') {
        return action(dispatch, getState);
    }
    return next(actions);
}

export default thunk;

使用传入的是active

store.dispatch(function(dispatch){
            setTimeout(function(){
                dispatch({type: 'INCREMENT'})
            }, 5000)
        })

理解

const thunk = function({dispatch, getState}){
    return function (next) { //dispatch = middleware(midApi)(store.dispatch);
        return function (action) {
            if (typeof action == 'function') {
                return action(dispatch, getState);
            }
            return next(actions);
        } 
    }
}

let next = store.dispatch;
store.dispatch = function dispatchAndLog(action) {
  console.log('dispatching', action);
  next(action);
  console.log('next state', store.getState());
}

多个连续异步

store.dispatch(function(dispatch){
            setTimeout(function(){
                console.log('1')
                dispatch(function(dispatch) {
                    setTimeout(function () {
                        console.log('2')
                        dispatch({type: 'INCREMENT'})
                    }, 2000)
                }) 
                
            }, 1000)
        })
        console.log('0')
redux-promise的源码,就会明白它内部是怎么操作的
export default function promiseMiddleware({ dispatch }) {
  return next => action => {
    if (!isFSA(action)) {
      return isPromise(action)
        ? action.then(dispatch)
        : next(action);
    }

    return isPromise(action.payload)
      ? action.payload.then(
          result => dispatch({ ...action, payload: result }),
          error => {
            dispatch({ ...action, payload: error, error: true });
            return Promise.reject(error);
          }
        )
      : next(action);
  };
}

如果 Action 本身是一个 Promise,它 resolve 以后的值应该是一个 Action 对象,会被dispatch方法送出(action.then(dispatch)),但 reject 以后不会有任何动作;如果 Action 对象的payload属性是一个 Promise 对象,那么无论 resolve 和 reject,dispatch方法都会发出 Action。

使用有两种方式:

第一种穿promise然后返回action

store.dispatch(
    new Promise((resolve, reject)=> {
                setTimeout(()=> {
                    console.log(1);
                    resolve('sss')
                }, 2000)
            }).then(response => { return {
                type: 'INCREMENT',
                payload: response
              }})
        )

一种是在把传入的active的payload生成promise

store.dispatch(
        {
            type:'INCREMENT',
            payload: new Promise((resolve, reject)=> {
                setTimeout(()=> {
                    console.log(1);
                    resolve('sss')
                }, 2000)
            }).then(function(data) {
                return data;
            })
        }
    )
posted @ 2018-02-24 21:25  快乐~  阅读(213)  评论(0编辑  收藏  举报