什麼是 Redux:設計師指南
已發表: 2022-03-10你聽說過 Redux 嗎? 它是什麼? 請不要谷歌搜索!
- “花哨的後端東西。”
- “我聽說過,但我不知道它是什麼。 也許它是一個 React 框架?”
- “在 React 應用程序中存儲和管理狀態的更好方法。”
我已經向 40 多名設計師提出了這個問題。 以上是他們的典型回答。 他們中的許多人都知道 Redux 與 React 一起工作,它的工作是“狀態管理”。
但是你知道這個“狀態管理”的真正含義嗎? 你知道 Redux 的真正力量不只是管理狀態嗎? 你知道Redux 不一定需要 React 才能工作嗎? 你想加入你的團隊關於是否使用 Redux 的討論(或至少午餐聊天)嗎? 您想在設計時考慮到 Redux 的工作原理嗎?
在本文的幫助下,我想向您展示 Redux 的全貌:它可以做什麼,為什麼要做它,有什麼缺點,什麼時候使用它,以及它與設計的關係。
我的目標是幫助像你這樣的設計師。 即使您之前沒有編寫過任何代碼,我認為理解 Redux 仍然是可能的並且有益(並且有趣)的。 期待簡單的英語和塗鴉——沒有代碼或抽象的談話。
準備好騎行了嗎?
什麼是 Redux?
在超高層次上,Redux 是開發人員用來讓他們的生活更輕鬆的工具。 你們中的許多人可能已經聽說過,它的工作是“狀態管理”。 稍後我將解釋狀態管理的含義。 在這一點上,我會給你留下這張照片:

你為什麼要關心?
Redux 更多的是關於應用程序的內部運作,而不是它的外觀。 這是一個有點複雜的工具,學習曲線陡峭。 這是否意味著我們作為設計師應該遠離它?
不,我認為我們應該接受它。 汽車設計師應該了解發動機的用途,對吧? 為了成功設計應用程序界面,設計師還應該對底層事物有紮實的了解。 我們應該了解它可以做什麼,了解開發人員使用它的原因,並了解它的優點和含義。
“設計不僅僅是它的外觀和感覺。 設計就是它的運作方式。”
——史蒂夫·喬布斯
Redux 能做什麼?
許多人使用 Redux 來管理 React 應用程序中的狀態。 這是最常見的用例,Redux 改進了 React 做得不好的方面(還)。
但是,您很快就會發現 Redux 的真正威力遠不止於此。 讓我們從了解狀態管理的真正含義開始。
狀態管理
如果你不確定這個“狀態”是什麼意思,讓我們用一個更通用的術語來代替它:“數據”。 狀態是不時變化的數據。 狀態決定了用戶界面上顯示的內容。
狀態管理是什麼意思? 一般來說,我們需要在應用程序中管理三個方面的數據:
- 獲取和存儲數據
- 將數據分配給 UI 元素
- 更改數據
假設我們正在構建一個 Dribbble 投籃頁面。 我們要在頁面上顯示的數據是什麼? 它們包括作者的個人資料照片、姓名、動畫 GIF、心數、評論等。

首先,我們需要從雲中的服務器獲取所有這些數據並將其放在某個地方。 接下來,我們需要實際顯示數據。 我們需要將這些數據的片段分配給相應的 UI 元素,這些元素代表我們在瀏覽器中實際看到的內容。 例如,我們將頭像的 URL 分配給 HTML img
標籤的src
屬性:
<img src='https://url/to/profile_photo'>
最後,我們需要處理對數據的更改。 例如,如果用戶向 Dribbble 投籃添加新評論或添加星標,我們需要相應地更新 HTML。
協調狀態的這三個方面是前端開發的重要組成部分, React 對此任務有不同程度的支持。 有時,React 中的內置工具運行良好。 但是隨著應用程序變得越來越複雜,它的狀態可能會變得更難單獨使用 React 來管理。 這就是為什麼許多人開始使用 Redux 作為替代方案的原因。
獲取和存儲數據
在 React 中,我們將 UI 分解為組件。 這些組件中的每一個都可以分解為更小的組件(請參閱“什麼是 React?”)。

如果我們的 UI 是這樣構造的,我們什麼時候獲取數據以及在填充 UI 之前將數據存儲在哪裡?
想像一下,每個組件中都有一個廚師。 從服務器獲取數據就像採購準備菜餚所需的所有原料。
一種天真的方法是在需要的地方和時間獲取和存儲數據。 這就像每個廚師出去直接從遙遠的農場購買蔬菜和肉類。

這種方法很浪費。 我們需要從許多組件多次調用服務器——即使是相同的數據。 廚師們來回走動會浪費大量的汽油和時間。
使用 Redux,我們獲取一次數據並將其存儲在一個中心位置,方便地稱為“存儲”。 然後,任何組件都可以隨時使用數據。 這與附近有一家超市沒什麼不同,我們的廚師可以在那裡購買所有食材。 超市派卡車從農場運回散裝蔬菜和肉類。 這比要求個別廚師親自去農場效率高得多!
這家商店也是唯一的事實來源。 組件總是從存儲中檢索數據,而不是從其他任何地方檢索數據。 這使所有 UI 內容保持一致。

將數據分配給 UI 元素
只有 React,實際上有更好的方法來獲取和存儲數據。 我們可以請我們非常友善的廚師 Shotwell 為他所有的廚師朋友購物。 他會開卡車去農場,把好吃的東西帶回去。 我們可以從容器組件中獲取數據,例如 Dribbble 示例中的“Shot”組件,並將其用作唯一的事實來源。

這種方法比從每個組件獲取數據的簡單方法更有效。 但肖特韋爾是如何將食材傳遞給其他廚師的呢? 如何將數據傳遞給實際呈現 HTML 元素的組件? 我們將數據從外部組件傳遞到內部組件,就像中繼中的指揮棒一樣,一直到數據到達目的地。
例如,作者頭像的 URL 需要從“Shot”傳遞到“ShotDetail”,再到“Title”,最後傳遞到<img>
標籤。 如果我們的廚師住在公寓裡,它真的是這樣的:

要將數據傳送到目的地,我們必須讓路徑上的所有組件都參與進來,即使它們根本不需要數據。 如果有很多樓層真的很煩人!
如果超市送貨上門怎麼辦? 使用 Redux 1 ,我們可以將任何數據插入到任何組件中,而完全不影響其他組件,如下所示:
1絕對準確地說,是另一個名為react-redux
的庫將數據交給 React 組件,而不是 Redux 本身。 但是由於 react-redux 只是做管道,人們幾乎總是一起使用 Redux 和 react-redux,我認為將其作為 Redux 的好處之一包括在內是很好的。

注意:在最新版本的 React (16.3) 中,有一個新的“上下文”API,它在將數據插入組件方面幾乎完成了相同的工作。 因此,如果這是您的團隊使用 Redux 的唯一原因,請認真考慮升級到 React 16.3! 查看官方文檔以獲取更多信息(警告:前面有很多代碼)。
更改數據
有時,在應用程序中更新數據的邏輯可能相當複雜。 它可能涉及多個相互依賴的步驟。 在更新應用程序狀態之前,我們可能需要等待來自多個服務器的響應。 我們可能需要在不同的時間、不同的條件下更新該州的許多地方。
如果我們沒有一個好的結構來處理所有這些邏輯,這可能會讓人不知所措。 代碼將難以理解和維護。
Redux 允許我們分而治之。 它提供了一種將數據更新邏輯分解為小的“reducer”的標準方法。 這些減速器和諧地協同工作以完成一個複雜的動作。


不過,請密切關注 React 的最新發展。 與“上下文”API 一樣,未來版本的 React 中可能會有一個新的“setState”API。 它可以更容易地將復雜的更新邏輯分解成更小的部分。 一旦這個新 API 可用,您可能不再需要 Redux 來管理狀態管理的這方面。
Redux 的真正力量
到目前為止,Redux 似乎只是 React 的一個創可貼。 人們使用 Redux 來改進 React(目前)做得不好的方面。 但 React 正在迅速追趕! 事實上,Redux 的創建者 Dan Abramov 幾年前就加入了 Facebook 的 React 核心團隊。 他們一直在忙於對 React 進行上述改進:上下文 API(在 16.3 中發布)、更好的數據獲取 API(在 2018 年 2 月演示)、更好的 setState API 等等。
它會讓 Redux 過時嗎?
你猜怎麼了? 我還沒有向你展示 Redux 的真正威力!

Redux 迫使開發人員遵循一些嚴格的規則,這給 Redux 帶來了很多力量(是的,紀律的力量!):
- 所有數據(應用程序狀態)都必須以明文形式描述。 您應該能夠用筆在紙上寫下所有數據。
- 每個動作(數據更改)都必須用明文描述。 在更改任何內容之前,您必須寫下您將要做什麼。 你不能在不留下標記的情況下更改數據。 這個過程在 Redux 俚語中稱為“調度動作”。
- 您更改數據的代碼必須表現得像數學公式。 給定相同的輸入,它必須返回相同的結果。 無論您運行多少次,4 的平方始終為 16。
當您遵循這些規則來構建應用程序時,奇蹟就會發生。 它實現了許多很酷的功能,否則這些功能很難實現或實現起來很昂貴。 這裡有些例子。 2
2我從 Dan Abramov 的帖子“你可能不需要 Redux”和他的“React Beginner Question Thread”中收集了這些示例。
撤銷重做
流行的撤消/重做功能需要係統級規劃。 因為撤消/重做需要記錄和重放應用程序中的每一次數據更改,所以您必須從一開始就在架構中考慮到它。 如果它是事後才完成的,則需要更改大量文件,這會導致無數錯誤。

因為 Redux 要求每一個動作都用明文描述,所以對 undo/redo 的支持幾乎是免費的。 如何使用 Redux 實現撤消/重做的說明放在一個簡單的頁面中。
協作環境
如果您正在構建一個類似於 Google Docs 的應用程序,其中多個用戶一起完成一項複雜的任務,請考慮使用 Redux。 它可能會為你做很多舉重。

Redux 使得通過網絡發送正在發生的事情變得非常容易。 接收另一個用戶在另一台機器上執行的操作、重放更改並與本地發生的事情合併是很簡單的。
樂觀的用戶界面
Optimistic UI 是一種改善應用程序用戶體驗的方法。 它使應用程序看起來在慢速網絡上響應更快。 這是需要實時響應的應用程序中的一種流行策略,例如第一人稱射擊遊戲。

舉個簡單的例子,在 Twitter 應用中,當你點擊一條推文上的心臟時,它需要請求服務器做一些檢查,例如,這條推文是否還存在。 該應用程序選擇作弊,而不是等待許多秒的結果! 它假設一切正常,並立即表現出一顆充滿活力的心。

這種方法有效,因為大多數時候一切都很好。 當事情不正常時,應用程序將恢復以前的 UI 更新並應用來自服務器的實際結果,例如,顯示錯誤消息。
Redux 以與撤銷和重做相同的方式支持樂觀 UI。 當從服務器接收到否定結果時,它可以輕鬆記錄、重播和恢復數據更改。
從狀態持久化和啟動
Redux 可以輕鬆地將應用程序中發生的事情保存在存儲中。 稍後,即使計算機重新啟動,應用程序也可以加載所有數據並從完全相同的位置繼續,就好像它從未被中斷過一樣。

如果您使用 Redux 構建遊戲,您只需要幾行代碼來保存/加載遊戲進度,而無需更改其餘代碼。
真正可擴展的系統
使用 Redux,您必須“調度”一個操作來更新應用程序中的任何數據。 這種限制使得它可以連接到應用程序中發生的幾乎所有方面。
您可以構建真正可擴展的應用程序,其中每個功能都可以由用戶自定義。 例如,查看 Hyper,一個使用 Redux 構建的終端應用程序。 “hyperpower”擴展在光標上添加了水花並搖動了窗口。 你喜歡這種“哇”的模式嗎? (也許不是非常有用,但足以打動用戶)

時間旅行調試
在調試應用程序時能夠及時旅行怎麼樣? 您運行應用程序,後退或前進幾次以找到錯誤發生的確切位置,修復錯誤並重新播放以確認。
Redux 讓開發者的這個夢想成真。 Redux DevTools 允許您通過拖動滑塊來將正在運行的應用程序的進度作為 YouTube 視頻來操作!
它是如何工作的? 還記得 Redux 強制執行的三個嚴格規則嗎? 這就是魔法的秘訣。

自動錯誤報告
想像一下:用戶發現您的應用程序有問題並想要報告錯誤。 她煞費苦心地回憶並描述了她所做的事情。 然後,開發人員嘗試手動執行這些步驟以查看錯誤是否再次出現。 錯誤報告可能含糊不清或不准確。 開發人員很難找到錯誤所在。
現在,這個怎麼樣。 用戶單擊“報告錯誤”按鈕。 系統會自動將她所做的事情發送給開發人員。 開發人員單擊“重放錯誤”按鈕並觀察該錯誤是如何發生的。 蟲子被當場壓扁,大家開心!
這正是使用 Redux Bug Reporter 時會發生的情況。 它是如何工作的? Redux 限制創造了奇蹟。

Redux 的缺點
Redux 強制執行的三大規則是一把雙刃劍。 它們啟用了強大的功能,但同時也帶來了不可避免的缺點。
陡峭的學習曲線
Redux 的學習曲線相對陡峭。 理解、記住和習慣它的模式需要時間。 如果您對 Redux 和 React 都是新手,不建議同時學習它們。
“樣板”代碼
在許多情況下,使用 Redux 意味著編寫更多代碼。 通常需要觸摸多個文件才能使一個簡單的功能正常工作。 人們一直在抱怨他們必須用 Redux 編寫的“樣板”代碼。
我知道,這聽起來很矛盾。 我不是說Redux 可以用最少的代碼實現功能嗎? 這有點像使用洗碗機。 首先,你必須花時間仔細地把盤子排成一排。 直到那時你才會看到洗碗機的好處:節省實際清洗碗碟、消毒碗碟等的時間。你必須決定準備時間是否值得!
績效處罰
由於其強制執行的限制,Redux 也可能對性能產生影響。 每當數據更改時,它都會增加一點開銷。 在大多數情況下,這沒什麼大不了的,而且放緩並不明顯。 儘管如此,當存儲中有大量數據並且數據頻繁更改時(例如,當用戶在移動設備上快速鍵入時),UI 可能會因此變得遲緩。
獎勵:Redux 不僅僅適用於 React
一個常見的誤解是 Redux 僅適用於React。 聽起來,如果沒有 React,Redux 什麼都做不了。 事實上,正如我們之前所討論的,Redux 在一些重要的方面對 React 進行了補充。 這是最常見的用例。
然而,事實上,Redux 可以與任何前端框架一起工作,例如 Angular、Ember.js 甚至 jQuery,甚至是 vanilla JavaScript。 試著用谷歌搜索,你會找到這個,這個,這個,甚至這個。 Redux 的一般思想適用於任何地方!
只要您明智地使用 Redux,您就可以在許多情況下獲得它的好處——不僅僅是在 React 應用程序中。

結論
與任何工具一樣,Redux 提供了權衡。 它支持強大的功能,但也有不可避免的缺點。 開發團隊的工作是評估權衡是否值得併做出有意識的決定。
作為設計師,如果我們了解 Redux 的優缺點,我們將能夠從設計的角度為這一決策做出貢獻。 例如,也許我們可以設計 UI 以減輕潛在的性能影響? 也許我們可以提倡包含撤消/重做功能以刪除大量確認對話框? 也許我們可以建議樂觀的 UI,因為它以相對較低的成本改善了用戶體驗?
了解一項技術的優勢和局限性,並據此進行設計。 我認為這就是史蒂夫喬布斯所說的“設計就是它的運作方式”。