4

注1:本文主要根据 "自述|redux中文文档" 学习的个人总结记录。也是是为了更快更好的学习和接受redux的操作,更好的应用的项目中。原文档地址:http://www.redux.org.cn/
注2:本文较长,可能会需要花一点时间去阅读和理解.

这篇文章主要介绍Redux中三个主要概念Action, Reducer, State。

1. Action

Action是我们事先定义好的一些对象,表示触发某个事件的标识。它必须有一个key为type字段,type的值类型为字符串,通常会单独建立一个文件存放所有的actionType,该文件定义的都是type的值.如下:

文件名:actionType.js

export const FIRST_ACTION = 'FIRST_ACTION'
export const MIDDLE_ACTION = 'MIDDLE_ACTION'
...

Action除了有个必须的type字段,我们还可以根据需要自定义一些其他的字段,这些字段承载着传入到store中,可以说是store中数据的唯一来源。 如下:

const DEMO_ACTION = 'DEMO_ACTION'  //这里就不单独的建一个文件存actionType

const action = {
    type: DEMO_ACTION,
    payload : '这里是可以传入到store中的数据'
}

store.dispatch(action) //通过store.dispatch将action传入到store

注意我们不会单独的为每次state的改变而去定义一个action,通常我们会声明一个action创建函数.

什么是action创建函数?其实就是生成action的方法,在redux中action创建函数只是简单的返回一个action:

function add() {
    return {
        type: 'ADD_WHAT',
        payload: {}
    }
}

store 里能直接通过 store.dispatch() 调用 dispatch() 方法,但是多数情况下你会使用 react-redux 提供的 connect() 帮助器来调用。bindActionCreators() 可以自动把多个 action 创建函数 绑定到 dispatch() 方法上。关于bindActionCreators这个方法我们后面会介绍到。

2.Reducer

刚才我们介绍的action是用来描述发生某个特定的事情去触发state的改变,那么reducer就是定义如何去操作我们state的规则。

reducer是一个纯函数,它接受两个参数,第一个是旧的state,第二个是action对象,运行后返回一个state。

    export function thisIsReducer(state={}, action) {
        switch(action.type) {
            case 'XXXX':
                //...
                return Object.assign({}, action.store)
                break
            case 'YYYY':
                //...
                return Object.assign({}, action.store)
                break
            default: 
                return state    
        }
    }

注意一下:我们不要去修改state,所以看到上面是通过Object.assign新建了一个副本.还有不管怎么样都要返回一个state。

  • 拆分reducer
    在日常的开发中,一个应用不会只有一个reducer,通常我们会分为多个小的reducer,每一个reducer管理着state树中某一个state项,例如:
//主题列表reducer
export function themeListStore(state={}, actions) {
  switch (actions.type) {
    case ActionsType.THEME_LIST:
      state = Object.assign({}, state, actions.store);
      state.datas.map((item, index)=>{
        state.datas[index].isChecked = false;
        item.photoList.map((e, i)=>{
          item.photoList[i].isChecked = 0;
          item.photoList[i].rotateAngle = item.photoList[i].userRotate;
        })
      });
      return state;
    case ActionsType.THEME_SORT:
      if( actions.dir == 'up' && actions.curId == 0 ) {
        return state
      }else if( actions.dir == 'down' && actions.curId == state.datas.length-1 ){
        return state
      }else {
        if( actions.dir == 'up' ){
          state.starId = state.datas[actions.curId].themeId
          state.endId = state.datas[actions.curId-1].themeId
          return state
        }else if( actions.dir == 'down' ){
          state.starId = state.datas[actions.curId].themeId
          state.endId = state.datas[actions.curId+1].themeId
          return state
        }
      }
    default:
      return state
  }
}

//切换照片批量移动和主题编辑增加reducer
export function changeOptStore(state=0, actions) {
  switch (actions.type) {
    case ActionsType.CHANGE_OPT:
      if(actions.option == 0){
        state = 0
        return state
      }else if(actions.option == 1){
        state = 1
        return state
      }else if(actions.option == 2){
        state = 2
        return state
      }
      console.log(state, 'state')
    default:
      return state
  }
}

上面的代码就是刚利用React-redux管理数据时写的reducer(有些不严谨的地方请忽略)。
注意每个 reducer 只负责管理全局 state 中它负责的一部分。每个 reducer 的 state 参数都不同,分别对应它管理的那部分 state 数据。
以上的只是一个文件中的reducer,一般更好的操作会根据不同的页面放到不同的文件中,保证其独立性,并用于处理不同的页面。

之前我们说过整个应用中只存在唯一的store,那么分散在不同文件中的reducer我们要如何整合在一起呢?
Redux提供了一个combineReducers()方法进行整合。

import {combineReducers} from 'redux';
import * as commonReducers from './commonReducers';
import * as alertMsgReducer from './alertMsgReducer';
import * as uploadPhotoReducer from './uploadPhotoReducer';
import * as photoGraphyReducer from './photoGraphyReducer';

const rootReducer = combineReducers({
  ...commonReducers,
  ...alertMsgReducer,
  ...uploadPhotoReducer,
  ...photoGraphyReducer
});
export default rootReducer;

如上,我们通过import引入不同文件中所有的reducer,然后通过combineReducers进行整合一个根reduce人、,然后export出去。那么整合过后的是什么东西呢?我们打印出来看下:

clipboard.png
如图,其生成的是一个函数,这个函数来调用你一系列的reducer,每个reducer根据它们的key来刷选出state中一部分数据并处理,然后这个生成的函数再将所有 reducer 的结果合并成一个大的对象。

3.Store

上面我们了解了action是预先定义好即将发生什么事件,reducer是定义对应事件处理数据的规则。那么store就是把他们联系到一起的对象:

  • store是保存应用中所有的state, store是单一的
  • store.getState()可以获取state
  • store.dispatch(action) 触发action,改变state
  • 通过 subscribe(listener) 注册监听器
  • 通过 subscribe(listener) 返回的函数注销监听器

如何去创建一个store?

import {createStore} from 'redux'
import rootReducerfrom './rootReducer'

let store = createStore(rootReducer)

createStore还有第二个参数,用来设置state的初始状态,那么这样对于同构应用可以进行服务端渲染(文档原话:这对开发同构应用时非常有用,服务器端 redux 应用的 state 结构可以与客户端保持一致, 那么客户端可以将从网络接收到的服务端 state 直接用于本地数据初始化。)

let store = createStore(todoApp, window.STATE_FROM_SERVER)
4.数据流

Redux中是严格的单项数据流。Redux中的从改变到渲染到页面中主要有四个步骤:

  • 在view层通过事件dispatch某个action(action是描述发生某个事情的对象)
  • Store调用传入的reducer函数,之前说过reducer会接受两个参数(之前的state和action对象)
  • 根reducer会把多个子reducer合并输出成一个单一的state树
  • Redux store 保存了根 reducer 返回的完整 state 树。
    这个新的树就是应用的下一个 state!所有订阅 store.subscribe(listener) 的监听器都将被调用;监听器里可以调用 store.getState() 获得当前 state。

clipboard.png
看上面,又找到一个感觉比较好的图可以表示我们的数据流向。这里就不重复的解释了,对照之前说的我相信可以看得清晰又明白~

总结

这里简单归纳一下:action是我们根据需要定义好一些action对象,我们通过store.dispatch(action)会触发队一行的reducer函数,reducer根据规则改变state,最后改变后的数据会呈现在我们的视图上。后面我们会继续介绍react中使用react-redux,以及异步action的操作等..


fsrookie
2.9k 声望256 粉丝

目前很多文章都是摘抄记录其他教程。见谅。