The Suspense is Killing Redux
譯文已獲得原作者授權,轉載時請附上原文連結 ofollow,noindex" target="_blank">https://medium.com/@ryanflorence/the-suspense-is-killing-redux-e888f9692430
在最近舉辦的 workshop 上我一直考慮這個問題:
Suspense 會殺死 Redux 嗎?
不得不說上面的表達方式過於粗魯,但我認為 Suspense 即將取代 Redux。
React Suspense
主要用來處理非同步資料請求時的頁面渲染,這方面是 Redux
未曾涉及的,但為了做到這一點, Suspense
需要去接管客戶端的資料邏輯,而這也正是 Redux
一直以來所擅長的。
如果你還沒有聽說過 React Suspense
,可以先花點時間聽下 Dan Abramov 在 JSConf 冰島上的關於 React Suspense 的分享 。
Suspense 的基本用法
使用 Suspense
分成三個部分:快取,資源請求和元件。
快取示例:
資源請求示例:
它僅需要接受一個返回 promise 的函式。如下是一個使用了上方的資源請求和快取的元件示例:
瞧,這就是 Suspense
這個應用的渲染過程的步驟如下:
- React 開始渲染(在記憶體中)。
- 呼叫
InvoicesResource.read()
。 - invoiceId 對應的快取資料不存在,從而觸發
createResource
函式的呼叫,傳送非同步請求去獲取資料。 - 然後,快取會 throw 第 3 步中返回的 promise。 (這裡能 throw 的除了異常,也可以是其他東西,甚至可以是
window
物件)這個 promise 被 React 捕獲之後,會暫停渲染過程。 - React 等待非同步請求結果(等待 promise resolve)。
- 非同步請求完成(promise resolve)。
- React 嘗試再次渲染
Invoices
(在記憶體中)。 - 再次呼叫
InvoicesResource.read()
。 - 此時已有資料快取,
ApiResource.read()
同步返回資料。 - React 渲染出頁面。
上方的步驟中,我們將非同步的資源請求邏輯當做同步函式呼叫,用起來非常炫酷。
而關於資源請求時如何處理佔位符和 Spinner,就不在這裡展開討論,我們只需要知道:React 將會維持在老的頁面,直到新的資料載入完成,當資源請求時間超時,可以先去渲染佔位符。
那麼在 Redux 中又是如何工作呢?
在 redux 中執行相同的流程的話,它會是這樣的:
對比一下
它們的工作方式不同,但也有些部分是相同的:
- store → cache
- mapStateToProps → Resource.read()
- action → function passed to resource
reducer 和 dispatch 函式不復存在,因為已不再需要通過 action 來更新 state,而是直接從資源請求中讀取資料。當(快取中)沒有資料時,會暫停渲染並等待資料請求返回。在某種程度上,cache + resources 同時充當了 dispatch,reducers 和 actions 的作用。
另外使用 Suspense
時不需要使用生命週期 hook 函式。當 invoiceId
改變而觸發 Invoice
重新渲染時,若該 invoiceId 對應的快取資料為空,則會自動傳送新請求去獲取資料,這比在生命週期 hook 函式中監聽 props 的變化再 dispatch 一個 action 要簡單得多。
依我看來,無論你之前是習慣使用 Redux store 還是元件層的 local state,切換到 Suspense
都會毫無壓力。
因此,如果你使用 Redux 主要用來獲取服務端資料並渲染的話,那麼 Suspense 完全可以替換掉 Redux。我會用 Suspense,因為它能讓程式碼更簡單,更好處理載入中的狀態。
快取失效怎麼辦
createCache
的第一個引數就是一個用於處理失效的函式。我測試下來發現,一旦快取資料更新,頁面就能根據新的資料直接重新渲染。這能客戶端資料快取和伺服器資料保持同步,看起來是不是很酷。
此外, Suspense
處理頁面更新的方式感覺很棒:新頁面在記憶體中渲染時,舊頁面仍然存在並且是可互動的,當資料更新後,頁面將使用新資料(來自服務端)重新渲染,要知道通常服務端渲染也是這樣工作的,這種方式也會讓同步客戶端和伺服器資料的中間層的存在失去意義。
Suspense
無法取代一切
有些人正在使用 Redux 做更復雜的事情(比如將狀態保持與 API 同步的同時也存到 localStorage 中 ), Suspense
也不能取代 Redux 的所有應用場景。
但是,依我看來,我所接觸的大多數正在使用 Redux 的人,僅僅是用來獲取伺服器端的資源資料,如果你也是其中一員的話,我想你會愛上 Suspense
的易用性和使用者體驗。
參加 workshop
本文作者 Ryan Florence 正在美國地區舉辦 React 相關 workshop, 點選檢視 workshop 城市和日期
譯者後記
本文中提到的例子,目前已可以使用最新發布的 react v16.6
版本體驗, react-cache
使用 canary 版本( react-cache
API 極不穩定,最新發布的 2.0.0-alpha.0
API 已改,請慎重使用 :joy:),完整示例程式碼可參考 https://github.com/foryuki/suspense-sample
1