摘要| Functional Redux Reducers with Ramda

原文地址react

Example Redux Reducer-----------------------

假設咱們要在 React 組件中展現一組 短吻鱷(gators)的列表,數據從 GatorAPI獲取, 具體的數據並不重要. 如今須要把 fetch 的數據添加到 redux 的 state 樹中redux

這個 state 的結構是數組

  • 在 all 數組中包括 gatorIds,沒有重複值(Ramda中如何實現惟一值?)
  • 在 lookup 添加新的 gator對象的 hash ById 索引, 索引值是 id(如何實現索引)
  • 在獲取數據成功之後, 改變 loading flag的狀態, 以便於在渲染時,去掉 spinning組件

Redux reducer的模式 Redux reducer 的模式實際上是固定的: (prevState,action)=>nextState 根據傳入的 action,對State 作出修改. 就這麼簡單, 修改是 Immutable的. 哪怕是一個數字加1, 也會造成新的 state, 這裏頗有必要使用 FB 的 Immutable.js. 若是是 prevState 和 nextState 之間有公共部分, 雖然是兩個不一樣的對象,可是在底層Immutable.js 能夠共享兩個對象的共同部分.注意這並非引用.bash

實例代碼

const reverseMerge = flip(merge);

export function fetchSuccess(state, { payload: { gators } }) {
   const gatorIds = map(prop("id"), gators);
   const gatorLookup = indexBy(prop("id"), gators);

   return evolve(
     {
       all: compose(uniq, concat(gatorIds)),
       byId: reverseMerge(gatorLookup),
       loading: always(false)
     },
     state
   );
 }
複製代碼

使用的 Ramda函數

always: Ramda 中一切都是函數, 若是想使用 int或者字符串,也有經過函數返回 always就是爲了這個出發點, val=()=>val,函數

compose 函數: 看家函數, Ramda數據流思考的方向, 數據從右傳入,通過一系列操做. 實例代碼中的 用法能夠翻譯爲 uniq(concat(gatorIds,all)),把 prevState 的 all 屬性取出,而後和遠程獲取的數據拼接, 使用 uniq 函數去重fetch

evolve: 接收兩個參數, 一組轉換函數, 一個對象, 函數對對象的屬性遞歸的進行處理spa

flip 函數: 翻轉兩個參數的位置, merge(a,b), 在 merge()中, 若是存在兩個屬性名相同, b對象的屬性值會覆蓋 a 的屬性值, 在 Redux中, 操做是merge(state,payload.data) 咱們但願在出現同名屬性的時候, payload 的屬性會覆蓋 state 的屬性. 可是在evolve函數中, state是做爲最後一個參數傳遞, 因此這裏藉助flip函數交換一下參數的位置.翻譯

indexBy 函數: 提取一個對象的鍵值做爲索引code

[{ id: 1, title: "one" }, { id: 2, title: "two" }]

{ 1: { id: 1, title: "one" }, 2: { id: 2, title: "two" } }
複製代碼

map 函數 , map(elem=>console.log(elm),elements)對象

merge 函數

prop 函數: 返回對象的屬性值,

prop("a",{a:"alligator",b:"bayou",c:"cayman"})
     
     //=> "alligator" 
複製代碼

uniq函數, 接收一個列表,返回一個新列表, 重複值被去除

再看看代碼

const reverseMerge = flip(merge);

export function fetchSuccess(state, { payload: { gators } }) {
   const gatorIds = map(prop("id"), gators);
   const gatorLookup = indexBy(prop("id"), gators);

   return evolve(
     {
       all: compose(uniq, concat(gatorIds)),
       byId: reverseMerge(gatorLookup),
       loading: always(false)
     },
     state
   );
 }
複製代碼
  1. 定義函數 reverseMerge,交換 merge 函數的參數
  2. map, gators列表, 應用 prop("id"),所以獲取到 ids列表
  3. indexBy函數返回的列表能夠經過 id屬性值做爲索引來訪問
  4. evolve 函數, 接收三個函數和 state, 三個函數分別對 state 的不一樣屬性作出修改
  5. state 中的all列表傳遞給 compose 函數和從 API獲取的 gatorIds 合併, 去重, 而後返回
  6. state中的 byId 對象傳遞給 reverseMerge 函數,和 gatorLookup 合併, 重複值會被 gatorLookup 的屬性值覆蓋到
  7. Loading的值被修改成 false.

結論

實際使用時還有不少的函數可使用, 在 Redux中有兩個地方,ramda能夠大有所爲,一個就是這裏, 還有一個地方就是container 組件包裝時對state的篩選 , mapStateToProps,

相關文章
相關標籤/搜索