從零開始擼一個Redux

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 由typepayload組成

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>
    );
  }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末河哑,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子龟虎,更是在濱河造成了極大的恐慌璃谨,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鲤妥,死亡現(xiàn)場離奇詭異佳吞,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)棉安,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進(jìn)店門底扳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人贡耽,你說我怎么就攤上這事衷模。” “怎么了蒲赂?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵阱冶,是天一觀的道長。 經(jīng)常有香客問我滥嘴,道長木蹬,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任氏涩,我火速辦了婚禮届囚,結(jié)果婚禮上有梆,老公的妹妹穿的比我還像新娘是尖。我一直安慰自己,他們只是感情好泥耀,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布饺汹。 她就那樣靜靜地躺著,像睡著了一般痰催。 火紅的嫁衣襯著肌膚如雪兜辞。 梳的紋絲不亂的頭發(fā)上迎瞧,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天,我揣著相機(jī)與錄音逸吵,去河邊找鬼凶硅。 笑死,一個胖子當(dāng)著我的面吹牛扫皱,可吹牛的內(nèi)容都是我干的足绅。 我是一名探鬼主播,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼韩脑,長吁一口氣:“原來是場噩夢啊……” “哼氢妈!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起段多,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤首量,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后进苍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體加缘,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年觉啊,在試婚紗的時候發(fā)現(xiàn)自己被綠了生百。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡柄延,死狀恐怖蚀浆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情搜吧,我是刑警寧澤市俊,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站滤奈,受9級特大地震影響摆昧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蜒程,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一绅你、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧昭躺,春花似錦忌锯、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春似舵,著一層夾襖步出監(jiān)牢的瞬間脚猾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工砚哗, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留龙助,地道東北人。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓蛛芥,卻偏偏與公主長得像泌参,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子常空,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評論 2 359