淺淺談Redux

Daniel_dx發表於2019-04-17

if 讀完了 then 你能瞭解到:

  • 好鋼用在刀刃 - redux的應用場景
  • 萬變不離其宗 - redux的基本思路

一些嘮叨

最近有個任務,就是需要在一個開源專案上進行擴充套件開發,而這個開源專案用到的是非常主流的 react 和 react-redux,近些年一直在跟 vue 打交道(廣告植入:比如開源了一個 vue 版本的 ncform 專案),冷落了 react 有一段時間了,剛好趁機重溫下 react 及其周邊相關的技術生態

react-redux,其實就是 redux 的 react 版本,方便 redux 在 react 中使用。

而 redux,是 javaScript 應用狀態管理容器,是參考 flux 設計模式的一種實現(vue 的 vuex 也是類似的實現),它獨立於各種 web 框架但又可融入於各種 web 框架。


哪裡才是 redux 用武之地

很多人會認為,引入 redux 會增加應用的複雜性。確實不簡單,但存在即合理,所以什麼場景下適合使用 redux 就很關鍵了。

我就開發一個活動頁。奉勸你不要用 redux 啦,一點好處都沒有,只會增加複雜性。

切記:不要為了用而用 - 然而現實中這種現象是大量存在的

當一個應用的功能越來越多時,開始進行功能模組拆分,這個時候,就會遇到一個問題,功能模組之間共享的資料如何處理,比如登入使用者的資訊。

例子能再具體點嗎?好吧,但還是登入使用者資訊,哈哈。

比如你在使用者模組修改了頭像,然後頂欄上的登入頭像要實時跟著更新,這個時候,其實是使用者模組和頂欄共享了你的使用者頭像資訊

解決這種可能有N種方法,今天既然聊 redux,那就專心講它吧

當你把資料梳理一下,你會發現有些資料是在模組內共享的,有些資料是在模組間共享的,我們將在模組間共享的稱之為應用級別的資料,即 Application 級別,redux 就是專門處理這種級別資料的解決方案


redux 的基本思路

我們用 redux 官方的 todo app 例子來講解( Warning: 僅為了說得簡單,講得明白,這種小應用是不適合引入 redux 的 )

你的應用有著一份描述著狀態(state)的資料,可能如下:

? 術語
State: 應用級別的狀態資料

{
  todos: [{
    text: 'Eat food',
    completed: true
  }, {
    text: 'Exercise',
    completed: false
  }],
  visibilityFilter: 'SHOW_COMPLETED'
}
複製程式碼

這份 state 是靜態的,你可以理解為就是應用最初的狀態。

當我完成了 Exercise 項,我就打個勾,表示我完成了。此時就需要更改下應用的狀態,需要把 Exercise 那一項 的completed 由 false 改成 true。

怎麼更改呢?直接把值改了不就完事了?

如果直接改變 state 物件的屬性值,就斷了 state 更改的軌跡,簡單講就是你修改了一個物件的屬性值,你就很難追蹤屬性值更改前是什麼樣子了。這在除錯排查問題的時候非常有用。

一定有更好的方法,可參考下事件的機制。所以當想更改狀態時,我們派發(dispath)一個操作(action),描述清楚我們想幹什麼,而不是直接就幹了。一個操作的描述可能如下:

{ type: 'ADD_TODO', text: 'Go to swimming pool' }
{ type: 'TOGGLE_TODO', index: 1 }
{ type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_ALL' }
複製程式碼

? 術語
dispatch: 通過該方法主動派發操作
action: 描述操作的內容,type 值必須提供,指定行為的型別,相當於事件的名稱

用派發操作的好處:
將每個更改描述為一個操作,讓我們清楚地瞭解應用程式中發生的情況。 如果發生了變化,我們就知道它為什麼會改變,操作就像麵包屑,使得應用狀態的變化有跡可循

OK,至此啥事還沒做,只是嘴上嚷嚷我要做什麼,那總得有實際處理的方法吧。

沒錯,這些實際修改狀態的方法稱為 reducer。實現可能如下:

function visibilityFilter(state = 'SHOW_ALL', action) {
  if (action.type === 'SET_VISIBILITY_FILTER') {
    return action.filter
  } else {
    return state
  }
}
function todos(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      return state.concat([{ text: action.text, completed: false }])
    default:
      return state
  }
}
複製程式碼

? 術語
reducer:它負責接收當前 state 和 action,然後按照 action 的 type,根據當前 state 進行操作,最終返回一個全新的 state(返回全新的 state 保證了 資料修改的可追溯性)。

你會發現 visibilityFilter 返回的是查詢條件字串,而 todos 返回的是列表項陣列列表。把它們返回的資料合併起來,就是一個完整的應用狀態,如下:

function todoApp(state = {}, action) {
  return {
    todos: todos(state.todos, action),
    visibilityFilter: visibilityFilter(state.visibilityFilter, action)
  }
}
複製程式碼

OK,到此為此,想幹什麼也說了,實際做事的也講了,但好像還是雲裡霧裡,腦袋裡依然沒有很清晰的全域性的畫面,好像還少了什麼東西。

告訴你,少了一個管家,它管著應用的狀態,它就是 store。

? 術語
Store: 管理應用狀態資料,負責把 action, reducer 等串起來

我們借用 redux 的一些 api 來完整描述一個資料修改的全過程

  1. 建立 store。通過 reducer 作為引數,store 就可以通過 reducer 獲取到應用狀態的資料結構
let store = createStore(todoApp)
複製程式碼
  1. 監聽變化。你可以在應用狀態發生變化時做一些事,比如更新DOM
function listener() { console.log(store.getState()) }
store.subscribe(listener)
複製程式碼
  1. 派發操作。因為 store 擁有 reducer,所以只要把 action 交給 reducer 處理即可。處理後可以通知執行第2步中訂閱的一些操作
let action = { type: 'ADD_TODO', text: 'Go to swimming pool' }
store.dispatch(action)
複製程式碼

?修改了好多次,終於寫完了。。。


寫在最後

接下來的內容跟本文一毛錢關係都沒,只是一如既往地打一波廣告:

ncform,一種令人愉悅的表單開發方式,僅需配置即可生成表單UI及其互動行為。
自帶豐富的 標準元件 和 校驗規則,開箱即用。
具備強大的 控制元件互動 和 擴充套件能力,做你所想。
github: github.com/ncform/ncfo…

注:目前只有 vue 版本,希望在不久的將來,有時間釋出 react 版本

tags: react, flux, react-redux, redux