一、基本概念
1.Store
Store 就是保存數(shù)據(jù)的地方襟企,你可以把它看成一個容器嘱么。整個應用只能有一個 Store。
2.State
Store對象包含所有數(shù)據(jù)顽悼。如果想得到某個時點的數(shù)據(jù)曼振,就要對 Store 生成快照。
這種時點的數(shù)據(jù)集合表蝙,就叫做 State拴测。
當前時刻的 State,可以通過store.getState()拿到府蛇。
3.Action
State 的變化集索,會導致 View 的變化。但是汇跨,用戶接觸不到 State务荆,只能接觸到 View。所以穷遂,State 的變化必須是 View 導致的函匕。Action 就是 View 發(fā)出的通知,表示 State 應該要發(fā)生變化了蚪黑。
Action 是一個對象盅惜。其中的type屬性是必須的,表示 Action 的名稱忌穿。其他屬性可以自由設置抒寂。
4.Action Creator
如下,addTodo就是一個Action Creator:
5.store.dispatch()
store.dispatch()是 View 發(fā)出 Action 的唯一方法掠剑。
6.Reducer
Store 收到 Action 以后屈芜,必須給出一個新的 State,這樣 View 才會發(fā)生變化。這種 State 的計算過程就叫做 Reducer井佑。
Reducer 是一個函數(shù)属铁,它接受 Action 和當前 State 作為參數(shù),返回一個新的 State躬翁。
實際應用中焦蘑,Reducer 函數(shù)不用像上面這樣手動調用,store.dispatch方法會觸發(fā) Reducer 的自動執(zhí)行姆另。
為此喇肋,Store 需要知道 Reducer 函數(shù),做法就是在生成 Store 的時候迹辐,將 Reducer 傳入createStore方法蝶防。
如上創(chuàng)建store對象后,以后每當store.dispatch發(fā)送過來一個新的 Action明吩,就會自動調用 Reducer间学,得到新的 State。
【擴展】
為什么這個函數(shù)叫做 Reducer 呢印荔?因為它可以作為數(shù)組的reduce方法的參數(shù)低葫。
附reduce執(zhí)行步驟:
actions.reduce(reducer,0)
reducer(state,action)
0作為第一個傳入的參數(shù),即仍律,初始的state === 0嘿悬,action === {type:'ADD',payload:0},執(zhí)行后水泉,返回值賦給state善涨,繼續(xù)取actions數(shù)組下一個成員,action === {type:'ADD',payload:1}草则,直到數(shù)組項全部取出钢拧,執(zhí)行完畢。total最終等于3炕横。
7.純函數(shù)
Reducer 函數(shù)最重要的特征是源内,它是一個純函數(shù)。也就是說份殿,只要是同樣的輸入膜钓,必定得到同樣的輸出。
由于 Reducer 是純函數(shù)卿嘲,就可以保證同樣的State颂斜,必定得到同樣的 View。
但也正因為這一點腔寡,Reducer 函數(shù)里面不能改變 State焚鲜,必須返回一個全新的對象掌唾,請參考下面的寫法:
【注意】
最好把 State 對象設成只讀放前。你沒法改變它忿磅,要得到新的 State,唯一辦法就是生成一個新對象凭语。
這樣的好處是葱她,任何時候,與某個 View 對應的 State 總是一個不變的對象似扔。
8.store.subscribe()
Store 允許使用store.subscribe方法設置監(jiān)聽函數(shù)吨些,一旦 State 發(fā)生變化,就自動執(zhí)行這個函數(shù)炒辉。
【設置監(jiān)聽】
state發(fā)生變化豪墅,會自動執(zhí)行l(wèi)istener。
【注意】
store.dispatch() ——> reducer自動執(zhí)行 ——> state更新 ——> listener自動執(zhí)行
顯然黔寇,只要把 View 的更新函數(shù)(對于 React 項目偶器,就是組件的render方法或setState方法)作為listener,就會實現(xiàn) View 的自動渲染缝裤。listener可以通過store.getState()得到當前狀態(tài)屏轰,這時可以setState(newState)。
【解除監(jiān)聽】
二憋飞、Store的實現(xiàn)
import { createStore } from 'redux';
let store =?createStore(reducer);
createStore方法還可以接受第二個參數(shù)霎苗,表示 State 的最初狀態(tài)。這通常是服務器給出的榛做。
let store = createStore(reducer, window.STATE_FROM_SERVER);
window.STATE_FROM_SERVER就是整個應用的狀態(tài)初始值唁盏。
【注意】
如果提供了這個參數(shù),它會覆蓋 Reducer 函數(shù)的默認初始值瘤睹。
【createStore方法的簡單實現(xiàn)】
三升敲、Reducer 的拆分
1.概述
由于,不同的action改變state不同的三個屬性轰传,并且驴党,這三個屬性之間沒有聯(lián)系,因此可以將這個reducer進行拆分获茬。
【說明】
chatLog港庄、statusMessage、userName是三個小的reducer恕曲。
當總的reducer被調用鹏氧,傳入action,小的reducer會被逐個執(zhí)行佩谣。
每個小reducer執(zhí)行把还,都會返回一個state:
(1)如果傳入的action,在當前的小reducer中,成功匹配到case吊履,則對state進行更新后安皱,返回新的state。
(2)如果傳入的action艇炎,在當前的小reducer中酌伊,沒有匹配到case,則走default缀踪,原封不動的返回state居砖。
總reducer返回值是一個對象,格式為驴娃,{reducerName1:state1,reducerName2:state2 ......}
【注意】
總reducer返回的對象里奏候,只有一個reducerName對應的是新的state(如果state的處理,按照上例的邏輯唇敞,返回Object.assign({ },state))鼻由,其他reducerName對應的都是舊的state,且指向同一地址厚棵。
2.【使用combineReducer進行reducers的合并】
【注意】
*上述寫法要求蕉世,State 的屬性名必須與子 Reducer 同名。
【個人理解】
這個要求是由es6對象的簡寫寫法+combineReducer的執(zhí)行機制婆硬,共同造成的狠轻。
(1)es6里,{chatLog,statusMessage,userName} 等同于 {chatLog:chatLog,statusMessage:statusMessage,userName:userName}
(2)combineReducer執(zhí)行機制:當store.dispatch彬犯,會觸發(fā)合成后的reducer(即chatReducer)自動執(zhí)行向楼。chatReducer執(zhí)行,返回的是
{
chatLog:chatLog(state.chatLog,action),
statusMessage:statusMessage(state.statusMessage,action),
userName:userName(state.userName,action)
}
這里谐区,state.依次讀取的屬性名湖蜕,就是傳入combineReducer的對象的屬性名。
*如果State 的屬性名與子 Reducer?不同名宋列,就要采用下面的寫法昭抒。
再次理解combineReducer執(zhí)行機制:
當store.dispatch觸發(fā)總reducer自動執(zhí)行時,傳入combineReducer的每一個子reducer會依次執(zhí)行炼杖、逐個執(zhí)行灭返。而傳入子reducer的參數(shù),就是state.[子reducer對應的key]和action坤邪。
3.combineReducer的簡單實現(xiàn)
4.實際使用
你可以把所有子 Reducer 放在一個文件里面熙含,然后統(tǒng)一引入。
四艇纺、栗子(計數(shù)器)
#整理自http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_usages.html