自己實現一個Redux。
阿新 • • 發佈:2018-11-24
Redux核心
Redux是一個用於狀態管理的js框架,是Flux架構的一種實現(如圖)。
Redux核心概念
- store
是一個物件,所有狀態集中儲存的地方,並全域性唯一,稱為狀態樹。幷包含以下幾個操作方法:getState()
獲取當前的狀態樹;dispatch(action)
分發一個動作,以改變狀態樹中對應的狀態;subscribe(listener)
新增一個監聽器,以監聽狀態樹的變化,當狀態樹變化時,會馬上執行傳入的函式。會返回一個unsubscribe函式,執行該函式可以解綁該監聽器。replaceReducer(nextReducer)
用於熱載入,暫時不重要。
- reducer
為一個使用者自定義的函式,在store分發(dispacth)action時提供處理方法去更新狀態樹中的狀態。應該為一個純函式。 - action
為一個使用者自定義的物件,裡面包含一個type屬性,標識一個動作型別。
核心概念總結:store是儲存所有狀態的地方,改變狀態的唯一方法就是通過呼叫store的dispatch方法分發相應的動作,該動作會經過每個使用者定義的reducer,reducer通過識別action的type,以及接收原來的狀態返回一個新的狀態。
redux核心api
createStore(reducer, initState)
根據使用者定義的reducer建立一個store。第二個引數為初始狀態,可選;combineReducers(reducers)
把使用者定義的多個reducer合併為一個。
逐步程式碼實現(涉及ES6語法):
createStore
1、createStore函式的大概樣子:
const createStore = (reducer, initState)=>{ const state = initState || {}; //初始狀態; return { //store的核心操作方法; getState(){ return state; } dispatch(action){} subscribe(){} }; }
2、dispatch(action)
方法實現:
dispatch方法是比較複雜的一個方法,應做的工作有:檢測action,檢測及防止dispatch死迴圈,觸發監聽器。
const createStore = (reducer, initState)=>{
let state = initState || {}; //初始狀態;
/* 新增程式碼 */
let inDispatch = false; //是否正在分發action
const listeners = []; //監聽器
/* *********** */
return { //store的核心操作方法;
getState(){
return state;
}
dispatch(action){
/* 新增程式碼 */
//1、檢測action合法性
if(!action || typeof action !== 'object' || !action.type){
throw new Error('action invalid');
}
//2、檢測是否正在分發,以防止在reducer中呼叫dispatch而導致死迴圈。
if(inDispatch){
throw new Error('can not dispatch a action now!');
}
//3、分發action
try{
inDispatch = true;
state = reducer(state, action);
}finally{
inDispatch = false;
}
//4、觸發所有監聽器
listeners.forEach(listener => listener());
/* *********** */
}
subscribe(){}
};
}
3、subscribe(listener)
方法實現:
subscribe方法除了新增監聽器之外,還應檢測重複監聽,返回一個解綁函式。
const createStore = (reducer, initState)=>{
let state = initState || {}; //初始狀態;
let inDispatch = false; //是否正在分發action
const listeners = []; //監聽器
return { //store的核心操作方法;
getState(){
return state;
}
dispatch(action){
//1、檢測action合法性
if(!action || typeof action !== 'object' || !action.type){
throw new Error('action invalid');
}
//2、檢測是否正在分發,以防止在reducer中呼叫dispatch而導致死迴圈。
if(inDispatch){
throw new Error('can not dispatch a action now!');
}
//3、分發action
try{
inDispatch = true;
state = reducer(state, action);
}finally{
inDispatch = false;
}
//4、觸發所有監聽器
listeners.forEach(listener => listener());
}
subscribe(listener){
/* 新增程式碼 */
if(listeners.some(item => item===listener))return; //檢測重複監聽
const pos = listeners.push(listener) - 1; //記錄該監聽器的位置
return ()=>{
//返回函式為刪除該位置的監聽器
if(listeners[pos] === listener){
listeners.splice(pos,1);
}
};
/* *********** */
}
};
}
這樣,Redux的核心功能就實現了。
combineReducers
實現combineReducers 應該考慮到多層、多個reducer的情況,並且能自動將action逐層分發至每個子reducer。
1、combineReducers大概的樣子:
const combineReducers = (reducers){
if(!reducers || typeof reducers !== 'object'){
throw new Error('invalid reducers.');
}
return (action)=>{};
}
2、關鍵程式碼實現:
const combineReducers = (reducers){
if(!reducers || typeof reducers !== 'object'){
throw new Error('invalid reducers.');
}
return (state, action)=>{
/* 新增程式碼 */
const newState = {};
for(key in reducers){
newState[key] = reducers[key](state[key], action);
}
return newState;
/* *********** */
};
}