當你開始詢問關于React和AJAX的一些東西時,專家們首先就會告訴你React只是一個View層的庫,它并沒有網絡及AJAX的相關功能。
這是對React很好的認識,但是對于你僅僅是想在React組件中獲取服務端數據并沒有什么幫助。
事實上,有很多方式可以這么做。也許你自己已經想過一些方法了,但是如果使用的方式不正確,那么代碼會變的混亂。
于是你會好奇,什么才是“正確”或者說是“較好”的方式呢?
在React組件中從服務端獲取數據的最佳實踐是什么呢
結論是...看使用場景。
四種方式
我收集了和React使用AJAX的四種方式。
具體使用哪種方式取決于你的開發規模及復雜度,并且還需要考慮你當前已經使用的類庫和技術方案。
1. 根組件
這是最簡單的實現方式,因此這種方式很適合做原型和小型的項目。
使用這種方式,你需要創建一個根/父組件來分發你所有的AJAX請求。這個根組件將AJAX返回的數據存它的state
中,然后將這個state(或是里面的一部分)作為props傳到子組件中。
這種方式的例子可以看下官方的React教程。CommentBox
組件就是發送所有AJAX請求的根組件。
我不太喜歡官方教程的地方是:他們還使用jQuery來發送AJAX請求。jQuery包含了很多功能的大類庫,因此不太理解為什么他們只是為了發送AJAX請求還使用jQuery。
我推薦使用fetch()
。它是更加簡單標準的Javascript AJAX API。Chrome和Firefox已經支持這個API并且使用polyfills也可以支持node和其他瀏覽器。想了解更多細節或者想更好的選擇你的AJAX庫,可以看看我的AJAX庫對比這篇文章。
警告:如果你的場景中是一個深層次的組件樹(子組件包含子組件包含子組件...)那么就數據從根組件傳遞到深層次的組件將是一個很長的過程。
根組件方式適用條件:
- 必須是淺層次的組件樹
- 不使用Redux或者Flux
2. 容器組件
一個容器組件“為展示組件和其他容器組件提供數據及行為”。如果你之前沒有聽說過這些概念,我推薦Dan Abramov關于presentational and container components的文章。
為了實現我們所需要的效果,容器組件這種方式和根組件方式類似, 除了根組件這種實現方式中多個組件可以與服務器端進行數據交互。
這種方式的原理是這樣的:對于所有需要從服務端獲取數據的展示組件,都為之創建一個容器組件來發送AJAX請求獲取數據,然后將這些數據通過屬性傳至子組件。
舉一個具體的列子,假設你需要展示一個包含名稱和圖片的用戶信息。
先創建一個 <UserProfile />
展示組件來接收name
和一個profileImage
屬性。這些組件中不需要包含任何的AJAX功能代碼。
然后創建一個<UserProfileContainer />
組件來接收userId
。它會將特定用戶的數據獲取到然后通過屬性傳到<UserProfile />
。
容器組件中的AJAX請求可以通過簡單的AJAX庫來處理。我推薦fetch()。
容器組件處理AJAX適用條件:
- 組件樹很深
- 大部分組件不需要從服務端獲取數據,但是某些組件需要
- 需要從不同的API、端獲取數據
- 沒有使用Redux/flux,并且你更加喜歡組件中使用'異步操作'
3. Redux異步Action
Redux管理數據,AJAX從服務端提供數據,這就很容易理解使用Redux可以處理網絡請求的問題。
如果你正在使用Redux,不要將AJAX放在你的React組件中。應該將它放到你的異步操作中。
我推薦使用fetch()來發送網絡請求,這也是Redux官方文檔中使用的方式。他們提供了使用Redux,React和fetch()的例子example reddit API。
如果你使用的是flux實現方式也差不多,在actions中發送網絡請求。
Redux異步Actions適用條件:
- 使用了Redux
- 使用了flux,實現方式類似
4. Relay
通過Relay,你可以使用GraphQL來聲明React組件需要的數據,Relay會自動將數據下載并填充到組件的屬性中。
Relay在大型app中使用的效果很好,但是需要大量的前期投入。需要:
- 學習Relay和GraphQL
- 使用GraphQL指定React組件需要的數據(取代propTypes)
- 建立一個GraphQL服務器
Relay僅僅是為了與GraphQL服務器進行通信,它不會幫你處理任何與第三方API的通信。
目前Relay只能與單個GraphQL服務器進行通信,因此如果你有多個數據源,那這種方式并不適合。與多個服務端進行數據通信的能力會在未來加上,已經在這個github issue中深入討論。
如果打算使用這種方式,這個Relay Playground是初步弄清楚Relay工作原理的好地方。
Relay適用條件:
- 創建大型應用擔心Relay的設計所解決的問題
- 還未創建JSON API
- 打算創建GraphQL服務器
- 應用只需要與單一的服務器進行通信
福利:反模式
假設以上的方式都是正確的,那么哪些方式是不推薦的呢?我建議避免使用以下兩種方式。
反模式1:在展示組件中使用AJAX請求
不要將AJAX邏輯添加到負責其他功能的組件中,比如負責復雜界面渲染的組件中。這樣做違反了關注點分離的設計原理。
反模式2:ReactDOM.render()
你可以把AJAX邏輯放到整個React之外,然后在接收到服務端更新的數據時調用ReactDOM.render()進行渲染。
這種方式也許看起來還不錯。我把它作為一種反模式是因為這種方式和根組件方式是類似的并且根組件的方式更加清晰。
結論
通過React創建的應用是模塊化的。React只是其中的一個模塊(譯者注:React僅是View)。AJAX庫是另外一個。這點與Rails和Angular不同。
你可能時常需要弄清楚有哪些其他模塊然后如何將它們組合到一起。
解決X問題最好的庫是什么、我如何在React中使用Y - 這些各式各樣的問題你都會在這個博客定期的更新中看到。
本文根據 @Andrew H Farmer的《React AJAX Best Practices》所譯,整個譯文帶自己的理解與想法,如果不妥之處及更優的譯法還請各位朋友指點。如需轉載此譯文,需注明英文出處http://andrewhfarmer.com/react-ajax-best-practices/。