Redux學習之二:從action到store?

redux裏面的概念不少,有Action、ActionCreator、reducer、store、middleware、Provider、Connect……概念不理解,就是眉毛鬍子一把抓,弄不出頭緒。redux的概念,經過一張圖你們就一目瞭然了。
圖片描述git

這張圖大體能夠歸納redux的整個流程。從圖中咱們能夠看出,Action是數據流動的開始,Reducer負責業務邏輯處理,store是整個流程的中軸。github

一、你從哪裏來?——談談actions的起源ajax

redux裏的action和flux裏的action大致上一致,不一樣的是設計理念的差異。flux裏的action是以函數的形式,但在redux裏,action被設計成普通的js對象。編程

{
type: 'ADD_TODO',
text: 'Build my first Redux app'
}
這就是一個最基本的action,必須注意的是,type是action必須的一個key值,是action的惟一標識。其它的key可使任意像傳遞的數據結構。
可是actions到底表明什麼?
actions表明着數據來源的萃取。咱們的view界面須要不少數據結構,如ajax返回的數據、路由狀態跟蹤、UI狀態等。。。關鍵的是這些數據都是動態流動的,既然流動,就要有入口、有方向。actions就是表明數據流動的開始,攜帶的key值中,type表明發生了什麼事情,其它的就是須要流動的數據結構。
概括起來,actions是數據從應用傳到store的有效載荷,是store惟一的數據來源。
那麼如何產生一個action,這就是又有一個概念actionCreator:redux

function addTodo(text) {數據結構

return {
type: ADD_TODO,
text
};

}
actionCreator其實是一個返回action值的函數而已。這樣,只需把 action 生成器的結果傳給 dispatch() 方法便可實例化 dispatch。app

dispatch(addTodo(text));

二、條條大路通哪裏?——看看reducer的神奇async

action表示發生了什麼事情,代表了有事情發生,確定會對應用的數據產生影響。咱們知道,React組件內的數據都是以state的形式存在的,state表明着數據結構。那麼就要問了,action的發生到底會對state產生什麼影響。這就是reducer的做用了。
reducer 實際上是一個函數, 接收舊的 state 和 action, 返回新的 state。ide

(previousState, action) => newState

這種設計來源於函數式編程思想,簡單,易懂,沒有反作用。函數式編程

function todoApp(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:

return Object.assign({}, state, {
  visibilityFilter: action.filter
});

default:

return state;

}
}
能夠看出,業務邏輯部分都是在reducer裏處理。這就涉及一個問題,一個應用裏有不少邏輯部分,都放在一個reducer裏面會形成很是的臃腫。實際過程當中,把業務進行分拆,而後經過combineReducer函數合併成一個reducer。詳細能夠看這裏:
https://github.com/rackt/redux/blob/mast...
切記,在reducer不要改變舊的state值。

三、看看你是誰?——揭開store的面紗

首先咱們看文檔裏怎麼描述的:

The Store is the object that brings themtogether.(them指的是action和reducer)

It’s important to note that you’ll only have a single store in a Redux application.

這就說明,Store負責把reducer和action結合的做用。store怎麼建立?通常是經過下面的代碼:

const store = createStore(reducer);
這個createStore又是什麼函數,咱們看看createStore.js源碼:

import isPlainObject from './utils/isPlainObject';
export var ActionTypes = {
  INIT: '@@redux/INIT'
};
export default function createStore(reducer, initialState) {
  if (typeof reducer !== 'function') {
    throw new Error('Expected the reducer to be a function.');
  }

  var currentReducer = reducer;
  var currentState = initialState;
  var listeners = [];
  var isDispatching = false;

  function getState() {
    return currentState;
  }

  function subscribe(listener) {
    listeners.push(listener);

    return function unsubscribe() {
      var index = listeners.indexOf(listener);
      listeners.splice(index, 1);
    };
  }

  function dispatch(action) {
    if (!isPlainObject(action)) {
      throw new Error(
        'Actions must be plain objects. ' +
        'Use custom middleware for async actions.'
      );
    }

    if (typeof action.type === 'undefined') {
      throw new Error(
        'Actions may not have an undefined "type" property. ' +
        'Have you misspelled a constant?'
      );
    }

    if (isDispatching) {
      throw new Error('Reducers may not dispatch actions.');
    }

    try {
      isDispatching = true;
      currentState = currentReducer(currentState, action);
    } finally {
      isDispatching = false;
    }

    listeners.slice().forEach(listener => listener());
    return action;
  }

  function replaceReducer(nextReducer) {
    currentReducer = nextReducer;
    dispatch({ type: ActionTypes.INIT });
  }


  dispatch({ type: ActionTypes.INIT });

  return {
    dispatch,
    subscribe,
    getState,
    replaceReducer
  };
}

咱們能夠看到createStore返回的是一個對象,該對象有四種方法,分別是:

dispatch,
subscribe,
getState,
replaceReducer

能夠看出redux裏的store有點像flux裏的dispatcher的做用,產生action能夠經過store.dispatch發送出去,想監聽狀態能夠經過store.subscribe訂閱。
值得注意的是,程序初始化的時候,redux會發送一個類型爲@@redux/INIT的action,來初始化state。

以上就是我對redux流程前半部分的理解,請批評指正。

相關文章
相關標籤/搜索