redux适用于很多场景,需要用到全局存储状态的应用都可以用到它,不管是换肤的应用还是购物车的场景,需要将不同的组件通过相同的状态关联起来,或者相同状态的变化触发不同视图的更新,都很适合用到redux。
目标
实现 redux 接口:
createStore
创建store,接受reducer函数和初始化的状态statecombineReducer
合并多个reducerbindActionCreator
转换action对象
分析
- reducer 作用:存放和管理状态
- dispatch 作用:触发状态修改
function reducer(state, action){
const {type, payload} = action;
switch(type){
case "add":
return {...state, count: state.count + payload}
default:
return state;
}
}
action
参数作为对象,需要拥有 type
和 payload
属性,reducer
通过判断 type
属性对state进行不同的合并操作并返回更新后的state
。
createStore
createStore 返回下面几个方法:
getState
: 获取最新state状态dispatch
: 触发状态更新subscribe
: 订阅视图更新函数
创建 createStore
支持 reducer 和 initState 作为参数:
function createStore(reducer, initState) {
// getState
let state = initState;
const getState = () => state;
// dispatch
const dispatch = (action) => {
if (!isPlainObject(action)) {
throw new Error('action 必须是纯对象')
}
if (typeof action.type == "undefined") {
throw new Error('必须定义action.type属性');
}
state = reducer(state, action);
// 更新完state,紧接着触发订阅方法
listeners.forEach(fn => fn());
return action
}
// 初始化值
dispatch({ type: "@@@Redux/INIT" })
// subscribe
const listeners = [];
const subscribe = (listener) => {
listeners.push(listener);
let subscribed = true;
return () => {
if (!subscribed) return;
let index = listeners.indexOf(listener);
listeners.splice(index, 1);
subscribed = false;
}
}
}
function isPlainObject(obj) {
if (typeof obj !== "object" || obj == null) return false;
let objPro = obj;
// 这里拿到obj最初始的__proto__
while (Object.getPrototypeOf(objPro)) {
objPro = Object.getPrototypeOf(objPro);
}
if (objPro === Object.getPrototypeOf(obj)) return true
}
combineReducer
合并 reducer
function combineReducer(reducers) {
let reducersKeys = Object.keys(reducers);
return function(state={},actions){
let combineState = {};
for(let i=0;i<reducersKeys.length;i++){
let key = reducersKeys[i]; // 拿到每个reducer的key值
let reducer = reducers[key]; // 拿到每个reducer方法
combineState[key] = reducer(state[key], actions);
}
return combineState;
}
}
bindActionCreator
目的:将actions
对象转换,把属性函数替换成能够执行的dispatch
方法:
function bindActionCreator(actions,dispatch) {
if(typeof actions === "function"){
return function(){
dispatch(actions.apply(this,arguments))
}
}
let actionCreator = {};
for(let name in actions){
actionCreator[name] = function(){
dispatch(actions[name].apply(this, arguments))
}
}
return actionCreator;
}
适用的场景中使用 redux 可以优化代码结构,提高可读性,不适用的场景反而会让应用变得复杂,不易理解。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。