Redux 和 React-redux 使用指南

2019-04-08  本文已影响0人  风之化身呀

1、引入Redux

 let store = createStore(todoApp, initialState, process.env.NODE_ENV === 'development' ? window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() : null)

注意点:
1、由于React代码都要经过webpack处理的,所以在写React代码的时候,可以大致看成代码环境处于Node.js,所以上述的process.env 对象也就可以看成全局变量了,从而可以写区分环境的代码。
2、createStore第一个参数是reducer,即combineReducer的结果;第二个参数表示store的初始状态(可选);第三个参数表示是否启用Redux调试工具(通常是chrome的一个扩展工具)
3、store是一个对象,当传入initialState时,其初始值由initialState决定;不传时,由combineReducer的参数(也是一个对象,记为O)决定。需要注意的是对象store的key由O决定,而不是initialState决定,initialState只能传和O有相同属性的值
4、store的运转过程:1、dispatch(actionCreator(payload));2、reducer处理对应的action,从而修改store
5、connect函数的两个参数:mapStateToProps(state,ownProps) 和 mapDispatchToProps(dispatch,ownProps)

const mapStateToProps = state => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}

const mapDispatchToProps = dispatch => {
  return {
    onTodoClick: id => {
      dispatch(toggleTodo(id))
    }
  }
}
const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

任何时候,只要 Redux store 发生改变,mapStateToProps 函数就会被调用。该回调函数必须返回一个纯对象,这个对象会与组件的 props 合并。如果你省略了mapStateToProps 这个参数,你的组件将不会监听 Redux store。如果指定了该回调函数中的第二个参数 ownProps,则该参数的值为传递到组件的 props,而且只要组件接收到新的 props,mapStateToProps 也会被调用(例如,当 props 接收到来自父组件一个小小的改动,那么你所使用的 ownProps 参数,mapStateToProps 都会被重新计算)。就是说不管store的变化是否是你关心的,你的mapStateToProps总是会被调用(即使这次调用是不必要的)
6、redux 如果不加中间件,则只能处理同步action

2、 Redux应用状态划分

{
  "id": "123",
  "author": {
    "id": "1",
    "name": "Paul"
  },
  "title": "My awesome blog post",
  "comments": [
    {
      "id": "324",
      "commenter": {
        "id": "2",
        "name": "Nicole"
      }
    },
   {
      "id": "325",
      "commenter": {
        "id": "3",
        "name": "Tom"
      }
    }
  ]
}

可以扁平化成这样:

{
  result: "123",
  entities: {
    "articles": {
      "123": {
        id: "123",
        author: "1",
        title: "My awesome blog post",
        comments: [ "324" ]
      }
    },
    "users": {
      "1": { "id": "1", "name": "Paul" },
      "2": { "id": "2", "name": "Nicole" }
    },
    "comments": {
      "324": { id: "324", "commenter": "2" }
    }
  }
}

所经过的操作如下:

import { normalize, schema } from 'normalizr';

// Define a users schema
const user = new schema.Entity('users');

// Define your comments schema
const comment = new schema.Entity('comments', {
  commenter: user
});

// Define your article
const article = new schema.Entity('articles', {
  author: user,
  comments: [comment]
});

const normalizedData = normalize(originalData, article);
    switch (action.type){
        case SET_VISIBILITY_FILTER:
            return {...state,visibilityFilter: action.filter}
        default:
            return state;
    }
}

2、Immutable.js 或者 Seamless-Immutable.js

3、实现

const createStore = reducer => {
    let state = null;
    const listeners = [];
    const getState = () => state;
    const subscribe = listener => listeners.push(listenter);
    const dispatch = action =>{
        state = reducer(state,action);
        listeners.forEach(listenter => listenter());
    };
    dispatch({});
    return {
        getState,
        dispatch,
        subscribe
    }
}
// 用法
const colorReducer = (state,action) => {
    if(!state){
        return {
            color:red
        }
    }else{
        switch(action.type){
            case 'modifyColor':
                return {
                  ...state,
                  color:action.color
              }
            default:
                return state;
        }
    }
}
const store = createStore(colorReducer);
store.dispatch({type:'modifyColor',color:'green'})
const applyMiddleWare = (...middlewares) => next =>{
    return (reducer,initialState) =>{
        let store = next(reducer,initialState);
        let dispatch = store.dispatch;
        let chain = [];
        let middlewares = middlewares;
        const middlewareAPI = {
            getState: store.getState,
            dispatch: action => dispatch(action)
        }
        chain = middlewares.map(value => value(middlewareAPI))
        dispatch = compose(...chain )(store.dispatch)
        return {
            ...store,
            dispatch
        }
    }
}

function compose(...funcs) {
    return arg => funcs.reduceRight((composed, f) => f(composed), arg);
}
const connect = (mapStateToProps,mapDispatchToProps) => WrappedComponent =>{
    class Connect extends Component {
        static contextType = {
            store: PropTypes.object
        }
        constructor(){
            this.state = {
                allProps:{}
            }
        }
        componentWillMount(){
            this._updateProps();
            this.context.store.subscribe(()=>this._updateProps());  // 订阅dispatch的变化,只要有dispatch,就会重新调用_updateProps,从而重新调用mapStateToProps和mapDispatchToProps触发React组件的生命周期,更新组件
        }
        _updateProps(){
            const store = this.context.store;
            const allProps = {};
            const mapProps = mapStateToProps(store.getState(),this.props);
            const mapDispatch = mapDispatchToProps(store.dispatch,this.props);
            this.setState({
                allProps: {
                    ...this.props,
                    ...mapProps,
                    ...mapDispatch
                }
            })
            
        }
        render(){   
            return <WrappedComponent ...this.state.allProps />
        }
    }
    return Connect
}

class Provider extends Component{
    static propTypes = {
        store: PropTypes.object,
        children: PropTypes.any
    }
    static childContextType = {
        store: PropTypes.object
    }
    getChildContext(){
        return {
            store:this.props.store || {}
        }
    }
    render(){
        return(
            <div>this.props.children</div>
        )
    }
}
// 签名:
({dispatch, store}) => (next) => (action) => {}

参考

上一篇下一篇

猜你喜欢

热点阅读