Redux 介紹指南


Redux介紹指南

本文轉載自:衆成翻譯
譯者:camiler
鏈接:http://www.zcfy.cc/article/770
原文:https://www.smashingmagazine.com/2016/06/an-introduction-to-redux/?utm_source=javascriptweekly&utm_medium=email

Redux是近期前端開發中最火的框架之一。然而,很多人不清楚它是什麼,它有什麼好處。

正如開發文檔中描述的,Redux對於JavaScript應用而言是一個可預測狀態的容器。換句話說,它是一個應用數據流框架,而不是傳統的像underscore.js或者AngularJs那樣的庫或者框架。

Redux是由Dan Abramov在大概2015年的時候創建的。是受到Facebook的Flux框架和函數式編程語言Elm的啓發。很快,Redux因其簡單易學開始流行起來,體積小(只有2KB)還有豐富的開發資料。如果你想知道Redux內部原理,想深入挖掘這個框架庫,建議查看Dan的免費課程

Redux最主要是用作應用狀態的管理。簡言之,Redux用一個單獨的常量狀態樹(對象)保存這一整個應用的狀態,這個對象不能直接被改變。當一些數據變化了,一個新的對象就會被創建(使用actions和reducers)。我們將在下面詳細介紹這些核心概念。

它是如何不同於MVC和Flux的?

爲了得到全面的認識,我們瞭解下傳統的模型-視圖-控制器(MVC)模式,大部分開發者都很熟悉。在MVC結構中,在數據(模型),表現層(視圖)和邏輯(控制器)之間是清晰分離的。這樣有個問題,尤其是在大型應用中:數據流是雙向的。就是說,在代碼許多地方,一個數據的改變(用戶的一個輸入或者接口返回)就會影響這個應用的狀態——比如,雙向數據綁定。而這將難以維護和調試。

Flux和Redux很相似。主要的不同在於Flux有多個可以改變應用狀態的store,它通過事件來廣播這些變化。組件可以訂閱這些事件來和當前的狀態同步。Redux沒有分發器dispatcher,但在flux中dispatcher被用來廣播數據到註冊的回調事件。另一個不同是Flux中有很多擴展是可用的,這也帶來了一些混亂和矛盾。

使用Redux的好處

你可能會問,“爲什麼我需要使用Redux?” 問得好。這裏列出了一些在你下個應用中使用Redux的好處:
* 可預測的結果
總有一個準確的數據源,就是store, 對於如何將actions以及應用的其他部分和當前的狀態同步可以做到絕不混亂。

  • 可維護性
    具備可預測結果的性質和嚴格的組織結構讓代碼更容易維護。

  • 組織性
    Redux對代碼應該如何組織更嚴苛,這讓代碼更一致,對團隊協作更容易。

  • 服務端渲染
    這非常有用,尤其是對於初次渲染,有助於更好的用戶體驗和搜索引擎優化。僅僅是把服務端創建的store傳遞給客戶端就行。

  • 開發者工具
    開發者可以實時跟蹤在應用中正在發生的一切,從actions到狀態的改變。

  • 社區和生態
    無論何時你學習使用任何庫或者框架這都是一個巨大的加分項。有個支持Redux的社區使它更吸引人來使用。

  • 易測性
    編寫可測試代碼的第一條準則是編寫可以只做一件事並且獨立的小函數。Redux的代碼幾乎全部都只是那樣函數:小,純粹,分離。

函數式編程

正如提到的,Redux是建立在函數式編程概念上的。理解這些概念對於理解Redux究竟是如何工作以及爲什麼那樣工作是非常重要的。我們來回顧下函數式編程的基本概念:

  • 它能把函數視爲第一類對象。

  • 它可以把函數當作參數。

  • 它可以使用函數、遞歸和數組來控制流程。

  • 它能使用純粹的,遞歸,高階,閉包以及匿名函數。

  • 它可以使用幫助函數,比如map、filter還有reduce。

  • 它可以將函數鏈式在一起。

  • 狀態不會改變(也就是說它是永恆不變的)。

  • 代碼的執行順序不重要。

函數式編程讓我們寫出更乾淨更模塊化的代碼。通過編寫更簡潔的、作用域和邏輯分離的函數,可以使代碼更容易測試,維護和調試。現在這些簡短的函數成爲可複用的代碼,這樣你可以少寫代碼,而更少的代碼是好事。函數可以在不做修改的情況下複製粘貼在任何地方。函數在作用域上是分離的,那樣就只執行一個任務,在一個APP中就可以少依賴其他模塊,這樣就減少了耦合性,這也是函數式編程的另一個好處。

01-functional-programming-opt-preview

函數式編程例子比喻 (來自: Tanya Bachuk) (大圖)
你將會看到除了其他東西之外,純函數,匿名函數,閉包,高階函數和鏈式調用經常應用於函數式JavaScript中。Redux最主要使用純函數,所以理解它們是什麼是非常重要的。

純函數根據傳參返回一個新的值。不修改現有對象,相反,返回一個新值。這類函數不依賴調用的state,而且不管提供的參數是什麼純函數只返回一個相同的結果。正因如此,它們是可預測的。

因爲純函數不修改任何值,所以它們不會對作用域有任何影響,也不會察覺到任何副作用,這意味着開發者可以只關心純函數返回的值。

Redux可用於何處?

大部分開發者會將Redux和React結合起來,但Redux可以和其他任何框架一起使用。例如,你可以將Redux和AngularJS, Vue.js, Polymer, Ember, Backbone.js 以及 Meteor搭配。雖然,Redux加React仍然是最常用的組合。確保以一個正確的順序來學習React:最好的入門資料是Pete Hunt的,這對於那些React纔開始起步以及對前端生態不知所措的開發者來說是非常有用的。JavaScript疲勞
是對前端開發者,無論是新人還是有經驗的老人,一種合理的擔憂,所以要以一個正確的順序正確的方式來花時間學習React或者是Redux。

Redux很讚的原因之一是它的生態圈。可以找到很多文章,學習指南,中間件,工具還有示例代碼。對我而言,我使用 David Zukowski的 示例代碼,因爲它涵蓋了一個需要用React,Redux和React-router建立javascript工程的所有東西。勸告一句:當學習像React和Redux這樣的新框架時儘量不要使用示例代碼庫和入門者錦囊。它會讓你更困惑,因爲你完全不懂它們是怎麼一起工作的。首先了解它,其次是建一個非常簡單的app,作爲一個支持項目從理論上學習,然後再使用示例代碼作爲生產項目來節約時間。

建立Redux部分

Redux概念聽起來可能比較複雜或者說是神奇,但它是簡單易懂的。記住這個庫只有2KB大。Redux有三個基本部分:動作(actions),存儲(store)和接頭(reducers)。

02-redux-data-flow-opt-preview

Redux數據流 (圖片來自: Tanya Bachuk) (查看大圖)

我們討論下每個部分做什麼。

Actions

簡單說來,動作就是事件。Actions傳遞來自這個應用(用戶接口,內部事件比如API調用和表單提交)的數據給store。store只獲取來自actions的信息。內部actions就是簡單的具有一個type 屬性(通常是常量)的JavaScript對象,這個對象描述了action的類型以及傳遞給store的負載信息。

{
  type: LOGIN_FORM_SUBMIT,
  payload: {username: ‘alex’, password: ‘123456}
} 

Actions通過action生成器創建。我知道這聽起來顯而易見。它們只是返回actions的函數。

function authUser(form) {
  return {
    type: LOGIN_FORM_SUBMIT,
    payload: form
  }
} 

要在應用裏任何地方調用actions,是很簡單的。使用dispatch方法,像這樣:

`dispatch(authUser(form));`

Reducers

我們已經討論過在函數式JavaScript中reducer是什麼。它基於數組reduce方法,接收一個回調(reducer)讓你從多個值中獲得單個值,整數和,或者一個一系列值的累積。在Redux中,reducer就是獲得這個應用的當前狀態和事件然後返回一個新的狀態的函數(純粹的)。理解接頭是怎樣工作的至關重要,因爲它們完成大部分工作。這裏是一個非常簡單的reducer,通過獲取當前狀態和一個action作爲參數,再返回下一個狀態:

function handleAuth(state, action) {
  return _.assign({}, state, {
    auth: action.payload
  });
} 

對於更多複雜的項目,使用Redux提供的combineReducers()實例是可行(必要、推薦)的。它把在這個應用中所有的reducer結合在一起成爲單個索引reducer。每一個reducer負責它自己那部分應用的狀態,這個狀態參數和其他reducer的不一樣。combineReducers()實例使文件結構更容易維護。

如果一個對象(狀態)只改變一些值,Redux就創建一個新的對象,那些沒有改變的值將會指向舊的對象而且新的值將會被創建。這對性能是極好的。爲了讓它更有效率你可以添加 Immutable.js

const rootReducer = combineReducers({
  handleAuth: handleAuth,
  editProfile: editProfile,
  changePassword: changePassword
}); 

Store

Store對象保存應用的狀態並提供一些幫助方法來存取狀態,分發狀態以及註冊監聽。全部狀態由一個store來表示。任何action通過reducer返回一個新的狀態對象。這就使得Redux非常簡單以及可預測。

 import { createStore } from ‘redux’;
  let store = createStore(rootReducer);
  let authInfo = {username: ‘alex’, password: ‘123456’};
  store.dispatch(authUser(authInfo)); 

開發者工具、代碼時空旅行(可回退的調試工具)以及熱重啓

爲了使Redux更容易配合工作,尤其是和大型應用配合時,我推薦使用 Redux DevTools。它非常有用,隨着時間展示狀態的改變,實時的改變,動作,以及當前的狀態。通過避免console.log當前的state和actions節約了你的時間精力。

03-redux-dev-tools-opt-preview

Redux DevTools (查看大圖)

Redux較於Flux有一點輕微的不同就是時空旅行的實現。在Redux中,你可以回到上一個狀態,甚至可以把你的狀態從那一點放到不同的位置上。在Redux工作流中,Redux DevTools支持這些 “時空旅行”特徵(把它們想成是針對狀態state的git命令):

  • 重置: 重置store創建的狀態

  • 恢復: 回退到上一次提交的狀態

  • 清除: 清除所有你可能搞錯來的已經改變了的有缺陷的actions

  • 提交: 使當前狀態爲初始狀態

時空旅行的這個特徵在生產上效率不高,而且僅僅是打算用在開發環境和調試中。DevTools也一樣。

Redux讓測試更容易,因爲它使用函數式JavaScript作爲基礎,而小的獨立函數容易測試。所以,如果你需要在你的狀態樹中改變一些東西,只導入一個負責那個狀態的reducer接頭就行了,然後再單獨測它。

建一個應用

讓我們來建一個非常簡單的使用Redux和React的應用來結束這個入門指南。爲了讓每個人都容易跟上,我保留原生的JavaScript,儘量少用ECMAScript2015和2016。在這篇文章中我們以比較容易的登錄邏輯開始。這個例子不會使用任何真實的數據,因爲這個應用的目的是來展示Redux是怎樣管理一個非常簡單的應用中的狀態的。我們使用CodePen編輯。

1. React組件

我們需要一些React組件和數據。我們寫一個簡單的組件再渲染render到頁面上。這個組件有個input字段和一個按鈕(一個分成簡單的登錄表單)。接下來,我們添加表示狀態的文本:

查看Redux介紹,由 Alex Bachuk (@abachuk) 在 CodePen上編寫。

2. 事件和動作

添加Redux模塊到工程中,添加按鈕的onClick 事件處理。一旦用戶登錄,我們就分發類型是LOGIN的action以及當前用戶的值。在我們完成那個之前,我們必須創建一個store並傳入一個reducer函數作爲它的一個參數。到目前爲止,這個reducer只是一個空的函數:

查看代碼Redux介紹 – 步驟2. 事件和動作, 由Alex Bachuk (@abachuk) 在CodePen上編寫的.

3. Reducers

現在我們有正激活的action,reducer將獲取這個action然後返回一個新的state。我們來處理LOGIN action返回一個已經登錄的狀態,並且添加一個LOGOUT 的action,便於我們後面使用它。auth reducer接收兩個參數:

  1. 當前的state (有個默認值),

  2. action.

查看代碼 Redux介紹 – 步驟3. Reducers ,由Alex Bachuk (@abachuk) 在CodePen上編寫.

4. 顯示當前狀態

現在,我們已經有初始狀態(在reducer中的默認值)以及React組件了,我們來看一下狀態是什麼樣的。最好的實踐就是將狀態累加到子組件中。因爲我們只有一個組件,所以我們將應用的狀態作爲一個屬性傳到auth組件。爲了讓所有的一起工作,我們必須用一個subscribe幫助方法註冊store監聽,通過將ReactDOM.render包裝在一個函數中並傳到store.subscribe()

查看Pen Redux介紹 – 步驟4. 顯示當前狀態 由Alex Bachuk (@abachukCodePen上實現.

5. 登錄和退出

既然我們有了登錄和退出action的處理方法,那我們來添加退出按鈕以及分發LOGOUT的action。最後一步就是管理哪個按鈕用來展示登錄,哪個用來退出,我們通過將登錄移到render方法的外面再渲染變量如下:

查看 Pen Redux介紹 – 步驟5. 登錄/退出 由 Alex Bachuk (@abachukCodePen上實現.

總結

Redux每天都在獲得吸引。它被用在很多公司 (Uber, Khan Academy, Twitter)以及項目中(Apollo, WordPress’ Calypso),實際生產項目中很成功。一些開發者可能會抱怨它有很多額外開銷。在大部分情況下,要表現簡單的像按鈕點擊的動作或者簡單的UI變化需要更多的代碼。或許簡單的動作以及UI變化不必是Redux store的一部分也能在組件級別上得到維護。

對於你的應用或者框架來說,儘管Redux可能不是完美的解決方案,但我強烈建議檢查一下,尤其是React應用。


發佈了51 篇原創文章 · 獲贊 33 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章