Redux 学习总结

1.Redux 设计理念

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

  全部的状态,保存在一个对象里面java

 

2.基本概念和API

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

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

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

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

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

  store.subscribe(listener);app

  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>
相关文章
相关标签/搜索