2018-05-25 Redux

三個(gè)原則

1.store是數(shù)據(jù)的唯一來源
2.state是只讀的
3.只能通過純函數(shù)改變state烈拒。

基于上述三點(diǎn)仆抵,下面來分析下這三個(gè)特點(diǎn)給我們編程過程中帶來的便利和麻煩架曹。

1. store是數(shù)據(jù)的唯一來源

便利:類比于觀察者模式莫杈。項(xiàng)目的各個(gè)部分只需要監(jiān)聽store 的變化诱鞠,就可以獲得相關(guān)信息挎挖。
麻煩:react中,數(shù)據(jù)流是自上而下單向的從父節(jié)點(diǎn)到子節(jié)點(diǎn)航夺。如果子節(jié)點(diǎn)要監(jiān)聽store的變化蕉朵,就需要從頂級(jí)父元素一層層傳遞到對(duì)應(yīng)的子節(jié)點(diǎn),增加了代碼的復(fù)雜性阳掐,降低了可讀性始衅。
解決方案:React—Redux里的Provider組件解決了這個(gè)問題。Provider組件使得子元素都可以獲得store缭保。connect組件將React組件和Redux store連接在一起汛闸。

2.state是只讀的

具體來說,只有通過發(fā)送action艺骂,才能改變state诸老,這樣將state的改變途徑限定了。而且action是一個(gè)純粹的對(duì)象彻亲,可以打印孕锄,或者存儲(chǔ)起來。

3.只能通過純函數(shù)改變state

首先說明下純函數(shù)的定義苞尝,純函數(shù)的返回值只會(huì)由輸入值決定。一樣的輸入宦芦,一樣的輸出宙址,state 的變化成為可預(yù)見的。并且輸入結(jié)果不會(huì)帶來其他變化调卑,例如抡砂,輸入值是一個(gè)對(duì)象大咱,純函數(shù)會(huì)返回一個(gè)新對(duì)象,而不會(huì)改變輸入的對(duì)象注益。
好處:可實(shí)現(xiàn)時(shí)間旅行碴巾。
解決方案:可以利用spread語(yǔ)法,或者Immutable庫(kù)來返回新對(duì)象丑搔。

關(guān)鍵概念

  1. store
  2. state
  3. action
  4. dispatch

store

store 保存應(yīng)用的state厦瓢,并且提供了四個(gè)方法。

  1. store.getState()獲得state啤月。
  2. store.dispatch(action)更新state煮仇。
  3. store.subscribe() 訂閱監(jiān)聽事件的發(fā)生。
  4. store.replaceReducer 替換reducer谎仲。

action

action 必須是plain object浙垫, 并且type是必傳項(xiàng)

// https://github.com/reduxjs/redux/blob/master/src/createStore.js
if (!isPlainObject(action)) {
      throw new Error(
        'Actions must be plain objects. ' +
          'Use custom middleware for async actions.'
      )
    }

    if (typeof action.type === 'undefined') {
      throw new Error(
        'Actions may not have an undefined "type" property. ' +
          'Have you misspelled a constant?'
      )
    }

dispatch

// https://github.com/reduxjs/redux/blob/master/src/createStore.js
   currentState = currentReducer(currentState, action)
// https://github.com/reduxjs/redux/blob/master/src/combineReducers.js
for (let i = 0; i < finalReducerKeys.length; i++) {
      const key = finalReducerKeys[i]
      const reducer = finalReducers[key]
      const previousStateForKey = state[key]
      const nextStateForKey = reducer(previousStateForKey, action)
      if (typeof nextStateForKey === 'undefined') {
        const errorMessage = getUndefinedStateErrorMessage(key, action)
        throw new Error(errorMessage)
      }
      nextState[key] = nextStateForKey
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey
    }
    return hasChanged ? nextState : state
  }

dispatch 一個(gè)action時(shí),所有的reducer都會(huì)執(zhí)行一次郑诺,然后reducer內(nèi)部有判斷action對(duì)應(yīng)的是否是當(dāng)前reducer夹姥。

例子

// action.js
export const ADD_PROJECT = 'ADD_PROJECT'
export const DELETE_PROJECT = 'DELETE_PROJECT'

export function addProject(data) {
  return { type: ADD_PROJECT, data } // action 是 a plain object
}

export function deleteProject(index) {
  return { type: DELETE_PROJECT, index }
}
// reducers.js

import {
  ADD_PROJECT, 
  DELETE_PROJECT,
} from './actions'

 
function projects(state = [], action) {
  switch (action.type) {
    case ADD_PROJECT:
      return [
        ...state,
        {
          id: state.length,
          data: action.data,
        }
      ]
    case DELETE_PROJECT:
      return state.filter((project) => {
        if (project.id !== action.index) {
          return project
        }
        return ''
      }).filter(v=>v)
     
    default:
      return state
  }
}
const rootReducers = combineReducers({
  projects
})

export default rootReducers
//store.js
import { createStore } from 'redux'
import rootReducers from './reducers'
 
const store = createStore(rootReducers)

優(yōu)化

一個(gè)項(xiàng)目只有一個(gè)store。隨著項(xiàng)目越來越大辙诞,reducers越來越多辙售,可以參考flux的命名空間的方式,將reducers按照功能分組倘要。 reducers可以分為兩級(jí)圾亏,第一級(jí)判斷是否是當(dāng)前命名空間的方法,第二級(jí)在當(dāng)前命名空間下的具體的數(shù)據(jù)處理方法封拧。

實(shí)踐經(jīng)驗(yàn)

在SPA應(yīng)用中志鹃,在不刷新頁(yè)面的前提下,各個(gè)路徑所對(duì)應(yīng)的頁(yè)面會(huì)共享store泽西。這樣在實(shí)際開發(fā)過程中曹铃,可能會(huì)導(dǎo)致無法準(zhǔn)確判斷,當(dāng)前頁(yè)面對(duì)數(shù)據(jù)請(qǐng)求是否正常捧杉。
例如陕见,a路徑請(qǐng)求了template相關(guān)數(shù)據(jù),直接跳轉(zhuǎn)到b頁(yè)面時(shí)味抖,這部分?jǐn)?shù)據(jù)已經(jīng)存在评甜,可以直接使用。但是如果用戶直接訪問b頁(yè)面仔涩,那么b頁(yè)面自己本身需要去請(qǐng)求template相關(guān)數(shù)據(jù)忍坷。所以為了避免這個(gè)盲區(qū),在自測(cè)階段,可以刷新這個(gè)頁(yè)面佩研,來確保每個(gè)頁(yè)面保證了數(shù)據(jù)獲取的正確性柑肴。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市旬薯,隨后出現(xiàn)的幾起案子晰骑,更是在濱河造成了極大的恐慌,老刑警劉巖绊序,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件硕舆,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡政模,警方通過查閱死者的電腦和手機(jī)岗宣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來淋样,“玉大人耗式,你說我怎么就攤上這事〕煤铮” “怎么了刊咳?”我有些...
    開封第一講書人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)儡司。 經(jīng)常有香客問我娱挨,道長(zhǎng),這世上最難降的妖魔是什么捕犬? 我笑而不...
    開封第一講書人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮碉碉,結(jié)果婚禮上柴钻,老公的妹妹穿的比我還像新娘。我一直安慰自己垢粮,他們只是感情好贴届,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蜡吧,像睡著了一般毫蚓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上昔善,一...
    開封第一講書人閱讀 51,115評(píng)論 1 296
  • 那天元潘,我揣著相機(jī)與錄音,去河邊找鬼君仆。 笑死柬批,一個(gè)胖子當(dāng)著我的面吹牛啸澡,可吹牛的內(nèi)容都是我干的袖订。 我是一名探鬼主播氮帐,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼洛姑!你這毒婦竟也來了上沐?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤楞艾,失蹤者是張志新(化名)和其女友劉穎参咙,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體硫眯,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蕴侧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了两入。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片净宵。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖裹纳,靈堂內(nèi)的尸體忽然破棺而出择葡,到底是詐尸還是另有隱情,我是刑警寧澤剃氧,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布敏储,位于F島的核電站,受9級(jí)特大地震影響朋鞍,放射性物質(zhì)發(fā)生泄漏已添。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一滥酥、第九天 我趴在偏房一處隱蔽的房頂上張望更舞。 院中可真熱鬧,春花似錦恨狈、人聲如沸疏哗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)返奉。三九已至,卻和暖如春吗氏,著一層夾襖步出監(jiān)牢的瞬間芽偏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來泰國(guó)打工弦讽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留污尉,地道東北人膀哲。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像被碗,于是被迫代替她去往敵國(guó)和親某宪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容