redux2 reducer action\ reducer\Store
Action
-
action是一个plain-object(平面对象)
- 他的__proto__指向Object。prototype
-
通常,使用payload属性表示附加数据(没有强制要求)
-
action中必须有type属性,改属性用于描述操作的类型
- 但是,没有对type的类型做出要求
-
在大型项目,由于操作类型非常多,为避免硬编译(hard code), 会将action 的类型存放到一个或一些单独的文件中(样板代码)
-
为了方便传递action,通常会使用action 创建函数来创建(action creator),来创建aciton
- action 创建函数应为无副作用的纯函数
- 不能以任何形式改动参数
- 不可以有异步
- 不可以对外部环境中的数据造成影响
- action 创建函数应为无副作用的纯函数
-
为了方便分发action redux 通过了一个函数
bindActionCreators
Reducer
Reducer 是用于改变数据的函数
-
一个数据仓库,有且仅有一个reducer, 并且通常情况下,一个工程只有一个仓库,因此,一个系统,只有一个reducer
-
为了方便管理,通常会将reducer放到单独的文件中
-
reducer被调用的时机
- 通过store.dispch 分发一个action, 此时,会调用reducer
- 当创建一个store的时候,会调用一次reducer
- 可以利用这一点,用reducer初始化状态
- 创建仓库时,不传递任何默认状态
- 将reducer的参数的state设置一个默认值
-
reducer 内部通常使用switch 来判断type值
-
reducer必须是一个没有副作用的纯函数
- 为什么要使用纯函数
- 纯函数有利于测试和调试
- 有利于还原数据
- 有利于将来与react结合是的优化
- 具体要求
- 不能改变参数,因此若要让状态变化,必须得到一个新的状态
- 不能有异步
- 不能对外部环境造成影响
- 为什么要使用纯函数
-
由于在大中型项目中,操作比较复杂,数据结构也比较复杂,因此,需要对reducer进行细分。
- redux 提供了方法,可以帮助我们更加方便的合并reducer
- combineReducers:合并reducer, 得到一个新的reducer, 该新的reducer管理一个对象,该对象中的每一个属性给对应的reducer管理
Store
Store: 用于保存数据
通过createStore 方法创建的对象。
该对象的成员
- dispatch :分发一个action
- getState:得到仓库中当前的状态
- replaceReducer:替换掉当前的reducer
- subscribe: 注册一个监听器,监听器是一个无参函数
- Symbol: (“observable”): Rxjs
createStore
/**
* 判断某个对象是否是一个plain-object
* @param {*} obj
*/
function isPlainObject(obj){
if(typeof obj !== 'object'){
return false;
}
return Object.getPrototypeOf(obj) === Object.prototype;
}
/**
* 得到一个随机数
* @param {*} length
*/
function getRandomString(length) {
return Math.random().toString(36).substr(2,length).split(" ").join(".")
}
/**
* 实现createStore功能
* @param {function} reducer
* @param {any} defaultState 默认的状态值
*/
export default function (reducer, defaultState) {
let currentReducer = reducer, //当前使用的reducer
currentState = defaultState //当前仓库的状态
const listeners = []; //记录所有的监听器
function dispatch(action){
//验证action
if(!isPlainObject(action)){
throw new TypeError("action must be a plain object")
}
//验证action的type是否存在
if(action.type === undefined) {
throw new TypeError("action must has a property of type")
}
currentState = currentReducer(currentState, action);
//运行所有的订阅者(监听器)
for (const listener of listeners) {
listener();
}
}
function getState() {
return currentState
}
/**
* 添加一个监听器
* @param {*} listener
*/
function subscribe(listener) {
listeners.push(listener); //将监听器加入到数组中
let isRemove = false; //是否已经移除
return function() {
if(isRemove){
return;
}
//将listener从数组中移除
const index = listeners.indexOf(listener);
listeners.splice(index, 1);
isRemove = true;
}
}
//创建仓库时,需要分发一次初始的action
dispatch({
type: `@@redux/INIT ${getRandomString(7)}`
})
return {
dispatch,
getState,
subscribe,
}
}
bindActionCreators
export default function (actionCreators, dispatch) {
if (typeof actionCreators === "function") {
return getAutoDispatchActionCreator(actionCreators, dispatch)
}
else if(typeof actionCreators === 'object'){
const result = {} //返回结果
for ( const key in actionCreators) {
if (actionCreators.hasOwnProperty(key)) {
const actionCreator = actionCreators[key]; //取出对应的属性值
if (typeof actionCreator === "function") {
result[key] = getAutoDispatchActionCreator(actionCreator,dispatch)
}
}
}
}
else {
throw new TypeError("acctionCretors must be an object or funtion which funtion")
}
}
/**
* 得到一个自动风发的action创建函数
*/
function getAutoDispatchActionCreator(actionCreators, dispatch) {
return function(...args){
const action = actionCreators(...args)
dispatch(action);
}
}