Redux中的reducer到底是什麼,以及它為什麼叫reducer?

作者:余博倫

轉載請提前溝通並註明出處。

Redux有3大核心概念:

  • Action
  • Reducer
  • Store

其中ActionStore都非常好理解,我們可以直接按照其字面意思,將他們理解為動作儲存

Action表示應用中的各類動作或操作,不同的操作會改變應用相應的state狀態,說白了就是一個帶type屬性的對象。

Store則是我們儲存state的地方。我們通過redux當中的createStore方法來創建一個store,它提供3個主要的方法,在這裡我們可以模擬一下createStore的源碼:

// 以下代碼示例來自redux官方教程nconst createStore = (reducer) => {n let state;n let listeners = [];n // 用來返回當前的staten const getState = () => state;n // 根據action調用reducer返回新的state並觸發listenern const dispatch = (action) => {n state = reducer(state, action);n listeners.forEach(listener => listener());n };n /* 這裡的subscribe有兩個功能n * 調用 subscribe(listener) 會使用listeners.push(listener)註冊一個listenern * 而調用 subscribe 的返回函數則會註銷掉listenern */n const subscribe = (listener) => {n listeners.push(listener);n return () => {n listeners = listeners.filter(l => l !== listener);n };n };nn return { getState, dispatch, subscribe };n};n

那麼剩下的這個reducer連翻譯都很難翻譯的東西應該怎麼理解呢?

我們注意到redux的官方文檔里專門有一句對reducer命名的解釋:

Its called a reducer because its the type of function you would pass to Array.prototype.reduce(reducer, ?initialValue)

中文版的文檔把這一句話翻譯成了:

之所以稱作 reducer 是因為它將被傳遞給 Array.prototype.reduce(reducer, ?initialValue) 方法。

我們要注意到這裡的中文翻譯理解其實是錯誤的。原文的本意並不是說redux里的reducer會被傳入到 Array.prototype.reduce 這個方法中。真的要翻譯的話,應該翻譯為:

之所以將這樣的函數稱之為reducer,是因為這種函數與被傳入 Array.prototype.reduce(reducer, ?initialValue) 的回調函數屬於相同的類型。

為什麼這麼講呢?我們來看一下array使用reduce方法的具體例子:

// 以下代碼示例來自 MDN JavaScript 文檔nn/* 這裡的callback是和reducer非常相似的函數n * arr.reduce(callback, [initialValue])n */nnvar sum = [0, 1, 2, 3].reduce(function(acc, val) {n return acc + val;n}, 0);n// sum = 6nn/* 注意這當中的回調函數 (prev, curr) => prev + currn * 與我們redux當中的reducer模型 (previousState, action) => newState 看起來是不是非常相似呢n */n[0, 1, 2, 3, 4].reduce( (prev, curr) => prev + curr );n

我們再來看一個簡單的具體的reducer的例子:

// 以下代碼示例來自redux官方教程nn// reducer接受state和action並返回新的statenconst todos = (state = [], action) => {n // 根據不同的action.type對state進行不同的操作,一般都是用switch語句來實現,當然你要用if...else我也攔不住你n switch (action.type) {n case ADD_TODO:n return [n // 這裡是ES7里的對象展開運算符語法n ...state,n {n id: action.id,n text: action.text,n completed: falsen }n ];n // 不知道是什麼action類型的話則返回默認staten default:n return state;n }n};n

如果非要翻譯reducer的話,可以將其翻譯為縮減器或者摺疊器?

為了進一步加深理解,我們再了解一下reduce是什麼東西,這個名詞其實是函數式編程當中的一個術語,在更多的情況下,reduce操作被稱為Fold摺疊(下圖來自維基百科)。

直觀起見,我們還是拿JavaScript來理解。reduce屬於一種高階函數,它將其中的回調函數reducer遞歸應用到數組的所有元素上並返回一個獨立的值。這也就是「縮減」或「摺疊」的意義所在了。

總而言之一句話,redux當中的reducer之所以叫做reducer,是因為它和 Array.prototype.reduce 當中傳入的回調函數非常相似。

當然,如果你認為這種命名不完美容易產生歧義,你完全可以去給redux提交一個PR,提供一種更加恰當的命名方式。

有任何好的意見或者是建議歡迎在評論區參與討論,如果文中有任何錯誤也歡迎在評論區批評指正。

參考資料

  • Why is a Redux reducer called a reducer?
  • Reducers
  • Reducer 中文文檔
  • Array.prototype.reduce()
  • Fold (higher-order function)

你也可以加入本專欄QQ群一起交流學習。QQ群號碼:591950591

更加歡迎將你的原創或翻譯文章投稿至本專欄。


推薦閱讀:

寫在2017的前端數據層不完全指北
Redux-Saga 初識和總結
如何規模化React應用
redux middleware 詳解

TAG:React | Redux | 前端开发 |