理解Redux

從 React 說起

剛開始接觸 React 的時候其實是感到非常驚艷的毡鉴,在 React 的架構下可以像搭積木一樣把前端的視圖組件組合在一起,非常好玩揭芍,React 這種模塊化的結構保證了組件內部的高度自治性羞秤,使得前端開發(fā)高度正交化。以至于剛剛使用 React 的時候簡直覺得是在上帝之手的幫助之下寫前端饭聚,觸手絲滑,效率飛起搁拙,但是用了一段時間之后就很快發(fā)現(xiàn)了一些問題秒梳,比如父組件可以通過給子組件賦值 props,但是子組件向父組件傳值卻只能通過較為復雜的雙向綁定箕速,如果要向不是父子關系的組件傳值怎么辦呢酪碘?React 的文檔會告訴你只能再 copy 一個組件過來了。EXM弧满?組件之間傳值這么常見的操作 React 卻只能給出一個這么簡單粗暴的辦法婆跑?負分此熬!差評庭呜!

但是知道了 Redux 這么一個神奇的存在之后,感覺 React 終于有救了犀忱,在 Redux 的框架之下募谎,所有的狀態(tài)被集中起來統(tǒng)一管理,使得應用內的數(shù)據(jù)完美地同步起來阴汇,再也不用擔心組件之間的通訊問題了数冬。

當然這里要提一下,Redux 本身是一個單獨的框架,跟 React 沒什么關系拐纱,但是由于在 React 的框架下視圖和 state 和 view 是一一對應的铜异,這樣就使得 Redux 更適用于 React 環(huán)境下的開發(fā)。

Redux 的基本思想

Redux 是一個基于Flux思想實現(xiàn)的一個針對web應用的狀態(tài)管理庫秸架,在Redux 里 Web 應用被視為一個有窮狀態(tài)機揍庄,在這個狀態(tài)機里所有狀態(tài)的變化都是可以追溯甚至是可以撤銷的,為了實現(xiàn)這樣的機制东抹,Redux 進行了以下三個約束:

  • 所有的 state 構成一棵 object tree蚂子,這棵 object tree 只存在于唯一一個store 中。
  • 所有state都是只讀的缭黔,唯一改變 state 的方法是觸發(fā) action
  • 使用純函數(shù)來執(zhí)行修改食茎,以保證每次對狀態(tài)修改的執(zhí)行結果都是一致的

在 redux 中主要引入了 action、reducer馏谨、store 這三個概念别渔,action 用于定義一個請求,reducer 用于根據(jù) action 產(chǎn)生新狀態(tài)惧互,store 用于存儲和管理 state钠糊,監(jiān)聽 action,將 action 自動分配給 reducer 并根據(jù) reducer 的執(zhí)行結果更新 state壹哺。

在這里你可以根據(jù)字面意思把 store 想象成一個倉庫抄伍,這個倉庫里的貨物就是 state ,但是這個倉庫的管理員實在是懶得跟自己的客戶溝通管宵,就請了好幾個助手來幫自己截珍,比如助手 A 專門負責某個手機廠商的請求,助手B專門負責電腦廠商的請求箩朴,他們計算好進出貨量之后通知管理員岗喉,管理員如果接到手機廠商的請求就把他分配給 A,接到電腦廠商的請求就分配給B炸庞,得到 A 和 B 的結果之后管理員就可以馬上更新倉庫了钱床,在這里這些助手就是 reducer,像手機和電腦廠商的請求就是 action埠居。執(zhí)行任務分配的這個過程就是 store.despatch(action) 函數(shù) 查牌。

Redux 的基本概念

Action

action 是把數(shù)據(jù)從應用傳到 store 的有效載荷。它是 store 數(shù)據(jù)的唯一來源滥壕。用來表明一個事件的發(fā)生纸颜,但并不對狀態(tài)如何修改做任何描述。一個action 的結構是一個 javascript 普通對象绎橘,一個 action 的結構如下

{
  //type字段用于標識action的類型胁孙,一般用一個字符串來表示
  type: 'ADD_TODO', 
  //text是用戶自定義的字段,一般用來傳遞和狀態(tài)修改相關的參數(shù)
  text: 'Build my first Redux app'
}

Reducer

action 只是描述了有事情發(fā)生了這一事實,但是并沒有指名如何更新 state涮较,reducer 就是對狀態(tài)修改過程的描述稠鼻,但是需要注意的有以下兩點:

  • 由于狀態(tài)是只讀的,reducer 本身并不能真正實現(xiàn)狀態(tài)的修改狂票,而是只把新狀態(tài)作為返回值返回枷餐。

  • 為了確保每次對狀態(tài)修改的結果都是一致的,reducer 必須是一個純函數(shù)苫亦,也就是說毛肋,只要是同樣的輸入,必定得到同樣的輸出屋剑。純函數(shù)需要遵循以下約束:

    不得改寫參數(shù)
    不能調用系統(tǒng) I/O 的API
    不能調用Date.now()或者Math.random()等不純的方法润匙,因為每次會得到不一樣的結果
    

    一個 reducer 的結構如下

/* 在這個 reducer 中,對于一個類型為 ADD_TODO 的 action唉匾,返回的新狀態(tài)是在傳入狀態(tài)數(shù)組中追加了一個元素 */
function todos(state = [], action) {
  switch (action.type) {
    case ADD_TODO:
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
      default:
          return state
  }
}

Store

在定義了描述事件發(fā)生的 action 和描述狀態(tài)修改方案的 reducer 之后孕讳,如何把它們聯(lián)系到一起真正實現(xiàn)狀態(tài)的改變呢?這就要牽扯到 store 啦巍膘,前面已經(jīng)提過 redux 的原則之一就是所有的 state 構成的對象樹都存到了 store 中厂财,除此之外 store 還有以下功能:

  • 維持應用的 state
  • 提供 getState() 方法獲取 state
  • 提供 dispatch(action)方法更新 state;
  • 通過 subscribe(listener)注冊監(jiān)聽器;
  • 通過 subscribe(listener)返回的函數(shù)注銷監(jiān)聽器峡懈。

創(chuàng)建一個 store 其實很簡單:

import { createStore } from 'redux'
import reducers from './reducers'
let store = createStore(reducers)

createStore() 的第二個參數(shù)是可選的, 用于設置 state 初始狀態(tài)璃饱。這對開發(fā)同構應用時非常有用,服務器端 redux 應用的 state 結構可以與客戶端保持一致, 那么客戶端可以將從網(wǎng)絡接收到的服務端 state 直接用于本地數(shù)據(jù)初始化肪康。

let store = createStore(todoApp, window.STATE_FROM_SERVER)                                                                                                                                                                                                                                                                                                                                                                                                                                   

接下來就可以簡單實現(xiàn)一個創(chuàng)建處理 action 的過程了

import { createStore } from 'redux'
const ADD_TODO = 'ADD_TODO' 
//創(chuàng)建一個 action 
const simpleAction1 = {
  type: 'ADD_TODO', 
  text: 'Build my first Redux app'
}
const simpleAction2 = {
  type: 'ADD_TODO', 
  text: 'Build my second Redux app'
}
//創(chuàng)建一個 reducer, 功能為收到類型為 ADD_TODO 的 action 后為在 state 中添加一個條目
function reducer(state = [], action) {
  switch (action.type) {
    case ADD_TODO:
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
      default:
          return state
  }
}
//創(chuàng)建一個初始狀態(tài)為空數(shù)組的 store 
let store = createStore(reducer,[])

// 打印初始狀態(tài)
console.log(store.getState())

// 每次 state 更新時荚恶,打印日志
// 注意 subscribe() 返回一個函數(shù)用來注銷監(jiān)聽器
let unsubscribe = store.subscribe(() =>
  console.log(store.getState())
)
// 發(fā)起一個 action, 執(zhí)行之后會更新狀態(tài),由于注冊了監(jiān)聽器你可以看到每次更新都會打印當前狀態(tài)
store.dispatch(simpleAction1)
store.dispatch(simpleAction1)

// 停止監(jiān)聽 state 更新
unsubscribe();
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末磷支,一起剝皮案震驚了整個濱河市谒撼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌雾狈,老刑警劉巖廓潜,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異善榛,居然都是意外死亡辩蛋,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門锭弊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來堪澎,“玉大人擂错,你說我怎么就攤上這事味滞。” “怎么了?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵剑鞍,是天一觀的道長昨凡。 經(jīng)常有香客問我,道長蚁署,這世上最難降的妖魔是什么便脊? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮光戈,結果婚禮上哪痰,老公的妹妹穿的比我還像新娘。我一直安慰自己久妆,他們只是感情好晌杰,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著筷弦,像睡著了一般肋演。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上烂琴,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天爹殊,我揣著相機與錄音,去河邊找鬼奸绷。 笑死梗夸,一個胖子當著我的面吹牛,可吹牛的內容都是我干的号醉。 我是一名探鬼主播绒瘦,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼扣癣!你這毒婦竟也來了惰帽?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤父虑,失蹤者是張志新(化名)和其女友劉穎该酗,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體士嚎,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡呜魄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了莱衩。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片爵嗅。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖笨蚁,靈堂內的尸體忽然破棺而出睹晒,到底是詐尸還是另有隱情趟庄,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布伪很,位于F島的核電站戚啥,受9級特大地震影響,放射性物質發(fā)生泄漏锉试。R本人自食惡果不足惜猫十,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望呆盖。 院中可真熱鬧拖云,春花似錦、人聲如沸应又。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽丁频。三九已至杉允,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間席里,已是汗流浹背叔磷。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留奖磁,地道東北人改基。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像咖为,于是被迫代替她去往敵國和親秕狰。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內容