Redux
Redux 屬于視圖狀態(tài)管理工具速和,它解決了傳統(tǒng) MVVM 架構(gòu)的 VM 層狀態(tài)管理責(zé)任過重的問題,他使用訂閱發(fā)布的模式剥汤,將 VM 層的狀態(tài)集中式的管理颠放,這樣做的好處有
- 視圖通訊變得簡單,多個視圖可以輕松共用狀態(tài)
- 代碼分割更加簡便
它有以下特點(diǎn)
- 不支持異步吭敢,派發(fā) action 的過程中碰凶,沒有實(shí)現(xiàn)
thunk
接口,不能實(shí)現(xiàn)阻塞 - 支持對 state 的 cbs(控制反轉(zhuǎn)) 風(fēng)格處理鹿驼,reducer 為函數(shù)
開始擼一個 redux
我們建立一個redux
文件夾欲低,然后在該目錄創(chuàng)建一個index.js
import createStore from "./core/createStore";
export default createStore;
接下來我們來實(shí)現(xiàn)createStore
方法,在該目錄下建立core
目錄畜晰,并在該目錄下建立createStore.js
文件砾莱,創(chuàng)建createStore
方法
createStore,創(chuàng)建一個
store
凄鼻,一個redux
架構(gòu)應(yīng)該只有一個store
腊瑟,該store
用于維持state
,派發(fā)action
块蚌,注冊監(jiān)聽器闰非,
redux 使用的是函數(shù)式編程,所以下面會用有一個閉包函數(shù)峭范,執(zhí)行后返回 redux 提供的 API
export default function createStore(reducer, preLoadState, enhancer) {
if (enhancer) {
// 中間件處理
return enhancer(createStore)(reducer, preLoadState);
}
function getState() {} // 獲取state
function subscribe() {}
function dispatch() {}
function replaceReducer() {}
// 告訴控制臺,初始化store 順便觸發(fā)reducer的default分支财松,拿到initialState
dispatch({ type: "REDUX_INIT" });
return {
getState,
subscribe,
dispatch,
replaceReducer,
};
}
A. getState (獲取狀態(tài))
getState 用于獲取 store 的 state,接下來我們來實(shí)現(xiàn) getState
方法
export default function createStore(reducer, preLoadState, enhancer) {
let currentState = preLoadState;
function getState() {
if (isDispatching) {
throw new Error("你不能獲取state纱控,因?yàn)楝F(xiàn)在正在派發(fā)action");
}
return currentState;
}
// ...
}
B. dispatch (調(diào)度)
dispatch 方法用于派發(fā)一個 action辆毡,action 由type
與payload
組成
export default function createStore(reducer, preLoadState, enhancer) {
let isDispatching = false;
let currentReducer = reducer;
let currentListeners = [];
let nextListeners = currentListeners;
function dispatch(action) {
try {
isDispatching = true;
// 處理傳入的action
currentState = currentReducer(currentState, action);
} finally {
isDispatching = false;
}
currentListeners = nextListeners;
const listeners = currentListeners;
// 遍歷訂閱者政敢,通知action已經(jīng)派發(fā)完成
listeners.forEach((lisntener) => listener());
return action;
}
// ...
}
C. subscribe (訂閱)
該方法用于提供給組件訂閱 store 的變化,當(dāng) store 發(fā)生變化時胚迫,既可在訂閱方法中更新視圖
export default function createStore(reducer, preLoadState, enhancer) {
let isSubscribed = false;
let nextListeners = [];
function subscribe(listener) {
nextListeners.push(listener);
return function unsubscribe() {
if (!isSubscribed) {
return;
}
if (isDispatching) {
throw new Error("不能在派發(fā)action的時候喷户,取消store的訂閱");
}
isSubscribed = true;
// 可以直接通過indexOf進(jìn)行函數(shù)的查找
const index = nextListeners.indexOf(listener);
// 刪除緩存中的訂閱函數(shù)
nextListeners.splice(index, 1);
};
}
// ...
}
D. replaceReducer (替換處理者)
用于替換 store 的 reducer 對象,這個方法沒什么特別的
export default function createStore(reducer, preLoadState, enhancer) {
function replaceReducer(nextReducer) {
currentReducer = nextReducer;
// 告訴控制臺访锻,替換了reducer
dispatch({ type: "REDUX_REPLACE" });
}
// ...
}
結(jié)束
這樣褪尝,我們就簡單的擼完一個 redux 了,我們以 React 為例子期犬,來看看如何使用它
// reducer
const reducer = (state = {}, action) => {
switch (action.tpye) {
case "TMD": {
// 對state進(jìn)行處理
state.name = "干啥啥不行";
return state;
}
default: {
return state;
}
}
};
const store = createStore(reducer);
import React from "react";
class App extends React.Component {
constructor() {
super();
this.state = store.getState();
}
componentDidMount() {
this.unscribe = store.subscribe(() => {
this.setState(store.getState());
});
}
render() {
const styleObj = {
background: "#66ccff",
width: "200px",
color: "#fff",
textAlign: "center",
cursor: "pointer",
};
return (
<ul>
以下是model的數(shù)據(jù) : <br />
<div style={styleObj} onClick={this.changeStore.bind(this)}>
點(diǎn)擊這里改變store數(shù)據(jù)
</div>
{JSON.stringify(this.state.model)}
</ul>
);
}
}