注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出去。那么整合过后的是什么东西呢?我们打印出来看下:
如图,其生成的是一个函数,这个函数来调用你一系列的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。
看上面,又找到一个感觉比较好的图可以表示我们的数据流向。这里就不重复的解释了,对照之前说的我相信可以看得清晰又明白~
总结
这里简单归纳一下:action是我们根据需要定义好一些action对象,我们通过store.dispatch(action)会触发队一行的reducer函数,reducer根据规则改变state,最后改变后的数据会呈现在我们的视图上。后面我们会继续介绍react中使用react-redux,以及异步action的操作等..
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。