zoukankan      html  css  js  c++  java
  • Redux 学习总结

    1.Redux 设计理念

      Web 应用是一个状态机,视图与状态是一一对应的

      所有的状态,保存在一个对象里面

    2.基本概念和API

      Redux 的核心就是 store, action, reducer   store.dispatch(action) ——> reducer(state, action) ——> final state

    (1)store 就是保存数据的地方,redux 提供createStore 函数,生成Store

        store = redux.createStore(reducer, []);

            store.getState() //返回store的当前状态

      Store 允许使用store.subscribe方法设置监听函数,一旦 State 发生变化,就自动执行这个函数。

      store.subscribe(listener);

      store.subscribe 方法返回一个函数,调用这个函数就可以解除监听

      let unsubscribe = store.subscribe(() =>

        console.log(store.getState())

      );

      unsubscribe(); //解除监听

      Store 的实现

    store.getState() //获取当前状态
    
    store.dispatch() //触发action
    
    store.subscribe() //监听state状态
    
    import { createStore } from ‘redux’;
    
    let { subscribe, dispatch, getState } = createStore(reducer, window.STATE_FORM_SERVER);
    
    window.STATE_FORM_SERVER //是整个应用的初始状态值

     (2)action 是一个普通的object,必须有一个type属性,表明行为的类型。

      const action = {

        type: ’add_todo’,

        text: ‘read’,

        time

        …

      }

      action描述当前发生的事情,改变State的唯一方法就是通过action,会将数据送到store。

      一般用actionCreator 工厂模式产生,View要发出的消息类型对应action的类型,手写起来很费劲。

      const ADD_TODO = “添加 todo”;

      function addTodo(text){

        return {

               type: ADD_TODO,

          text 

              }

      }

      const action = addTodo(‘Learn’);

      addTodo 方法就是一个Action Creator

      View 发出Action的唯一途径 store.dispatch(action) //触发事件 

     (3)reducer 其实就是一个普通函数,主要用来改变state. Store 收到View 发出的Action 以后,必须返回一个新的State,View 才会发生变化。 而这个计算新的State的过程就叫Reducer.

      const reducer = function(state, action){

      switch(state.text){

                 case ‘add_todo’:

      return state.contact(‘…’);

                  default:

      return state;

             }

      }

       当然实际开发不像上面例子这么简单,需要在创建state的时候就知道state的计算规则,将reducer传入:

      store = redux.createStore(reducer);

      Reducer 纯函数,只要有同样的输入必然返回同样的输出。不能改变原来的state而是通过Reducer返回一个新的state。

    //state 是一个对象
    
    function reducer(state, action){
    
    return Object.assign({},state, {thingToChange});
    
             return {…state, …newState};
    
    }
    
    //state 是一个数组
    
    function reducer(state, action){
    
    return […state, newItem];
    
    }

    3.Reducer的拆分和合并

    在实际项目中,reducer 很庞大,不易阅读管理,我们可以将reducer 拆分成小的函数,不同的函数对应处理不同的属性。然后将其合并成一个大的reducer

    Reducer 提供了一个方法combineReducers方法来合并reducer.

    const chatReducer = (state = defaultState, action = {}) => {
      return {
        chatLog: chatLog(state.chatLog, action),
        statusMessage: statusMessage(state.statusMessage, action),
        userName: userName(state.userName, action)
      }
    };
    
    import { combineReducers } from 'redux';
    
    const chatReducer = combineReducers({
      chatLog,
      statusMessage,
      userName
    })
    
    export default todoApp;

    你可以把所有子reducers 放在一个文件夹里,然后统一引入。

    import { combineReducers } from 'redux'

    import * as reducers from './reducers'

    const reducer = combineReducers(reducers)

    4.中间件和异步操作

    我们使用redux ,用户发出action,Reducer算出新的state,然后重新渲染界面。这里Reducer是立即算出state,立即响应的,同步执行的顺序。 

    可是如果我们需要执行异步实现,Reducer执行完之后,自动执行呢? 这里就需要用到middleWare(中间件)。

    中间件加在什么地方合适?我们来简单分析下。

    1. Reducer 是纯函数,用来计算state,相同的输入必然得到相同的输出,理论上纯函数不允许读写操作。

    2. View和state是一一对应,是state的呈现,没有处理能力。

    3. 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 和执行 Reducer 这两步之间,添加了其他功能。

    中间件的用法:

    const store = createStore(
      reducer,
      initial_state,
      applyMiddleware(logger)
    );

    createStore方法可以接受整个应用的初始状态作为参数,将中间件(logger)放在applyMiddleware方法之中,传入createStore方法,就完成了store.dispatch()的功能增强。

    applyMiddleware 是Redux 的原生方法,作用是将所有中间件组成一个数组,依次执行。下面是它的源码:

    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}
      }
    }

    可以看到,中间件内部(middlewareAPI)可以拿到getState和dispatch这两个方法。

    异步操作的一个解决方案,就是让 Action Creator 返回一个 Promise 对象。看一下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。

    5.React+Redux

    redux将所有组件分为UI组件和容器组件。

    UI 组件有以下几个特征。

    1. 只负责 UI 的呈现,不带有任何业务逻辑
    2. 没有状态(即不使用this.state这个变量)
    3. 所有数据都由参数(this.props)提供
    4. 不使用任何 Redux 的 API

    UI 组件又称为"纯组件",即它纯函数一样,纯粹由参数决定它的值。

    容器组件的特征恰恰相反。

      1.负责管理数据和业务逻辑,不负责 UI 的呈现

      2.带有内部状态

      3.使用 Redux 的 API

    React-Redux 提供connect方法,用于从 UI 组件生成容器组件。connect的意思,就是将这两种组件连起来。

    import { connect } from 'react-redux'

    const VisibleTodoList = connect(

      mapStateToProps,

      mapDispatchToProps

    )(TodoList)

    上面代码中,connect方法接受两个参数:mapStateToProps和mapDispatchToProps。

    它们定义了 UI 组件的业务逻辑。前者负责输入逻辑,即将state映射到 UI 组件的参数(props),后者负责输出逻辑,即将用户对 UI 组件的操作映射成 Action。

    6. react+redux 的 simple 示例

    原理图:

    <div id="container"></div>
    
    <script type="text/babel">
    
      //工厂Action
    
        var addTodoAction = function(text){
    
          return {
    
            type: 'add_todo',
    
            text: text
    
          }
    
        };
    
    
        var todoReducer = function(state,action){
    
          if(typeof state === 'undefined') return [];
    
          switch(action.type){
    
            case 'add_todo':
    
            return state.slice(0).concat({
    
              text: action.text,
    
              completed:false
    
            });
    
            default:
    
            return state;
    
          }
    
        };
    
    
        var store = redux.createStore(todoReducer);
    
    
        var App = React.createClass({
    
          //获取初始状态
    
          getInitialState: function(){
    
            return {
    
              items: store.getState()
    
            };
    
          },
    
          componentDidMount: function(){
    
            var unsubscribe = store.subscribe(this.onChange);
    
          },
    
          onChange: function(){
    
            this.setState({
    
              items: store.getState()
    
            });
    
          },
    
          handleAdd: function(){
    
            var input = ReactDOM.findDOMNode(this.refs.todo);
    
            var value = input.value.trim();
    
            if(value){
    
              store.dispatch(addTodoAction(value));
    
            }
    
            input.value = '';
    
          },
    
          render: function(){
    
            return(
    
              <div>
    
              <input ref="todo" type="text" placeholder="input todo type"/>
    
              <button onClick ={this.handleAdd}>Add</button>
    
              <ul>
    
              {
    
                this.state.items.map(function(item){
    
                  return <li>{item.text}</li>
    
                })
    
              }
    
              </ul>
    
              </div>
    
            );
    
          }
    
        });
    
        ReactDOM.render(
    
          <App />,
    
          document.getElementById('container')
    
        )
    
      </script>
  • 相关阅读:
    SVN 部署(基于 Linux)
    禅道部署(基于 Linux)
    MySQL 中文乱码问题
    设置 Linux 支持中文
    SQL 文件导入数据库
    虚拟 IP 设为静态 IP
    python selenium(定位方法)
    python selenium(环境搭建)
    「杂谈」苏州人不能太膨胀
    「SAP技术」如何看Z移动类型是复制哪个标准移动类型而创建的?
  • 原文地址:https://www.cnblogs.com/torri/p/6970535.html
Copyright © 2011-2022 走看看