首页 > Redux学习之二:从action到store?

Redux学习之二:从action到store?

redux里面的概念很多,有Action、ActionCreator、reducer、store、middleware、Provider、Connect……概念不理解,就是眉毛胡子一把抓,弄不出头绪。redux的概念,通过一张图大家就一目了然了。

这张图大致可以概括redux的整个流程。从图中我们可以看出,Action是数据流动的开始,Reducer负责业务逻辑处理,store是整个流程的中轴。

1、你从哪里来?——谈谈actions的起源

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:

function addTodo(text) {
    return {
    type: ADD_TODO,
    text
    };
}

actionCreator实际上是一个返回action值的函数而已。这样,只需把 action 生成器的结果传给 dispatch() 方法即可实例化 dispatch。

dispatch(addTodo(text));

2、条条大路通哪里?——看看reducer的神奇

action表示发生了什么事情,表明了有事情发生,肯定会对应用的数据产生影响。我们知道,React组件内的数据都是以state的形式存在的,state代表着数据结构。那么就要问了,action的发生到底会对state产生什么影响。这就是reducer的作用了。
reducer 其实是一个函数, 接收旧的 state 和 action, 返回新的 state。
(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/master/docs/basics/Reducers.md
切记,在reducer不要改变旧的state值。

3、看看你是谁?——揭开store的面纱

首先我们看文档里怎么描述的:

The Store is the object that brings them together.(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 });
  }

  // When a store is created, an "INIT" action is dispatched so that every
  // reducer returns their initial state. This effectively populates
  // the initial state tree.
  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流程前半部分的理解,请批评指正。

【热门文章】
【热门文章】