Relay: 全新的React數據獲取框架

React在前端領域開啓了一個新的時代。隨着Facebook發佈並開源React,它迅速成爲大量技術公司 運用在生產環境中的一款流行的庫。在本文中,我們將會討論的是一個全新的React附屬框架——Relay。

React中數據獲取存在的問題

由於React正在變得越發流行,使用React構建的項目的規模和複雜度也隨之增加。 由於React只是一個視圖層的庫,這使得某些團隊需要在不同的基礎設施上構建項目時會面臨很多未知的問題和挑戰。 基於這些痛點,Facebook也前瞻性的給予了很多技術支持和指導。

Flux

對於使用React的開發者而言,早期的主要痛點之一是事件處理。爲了解決這個問題,Facebook發佈了Flux, 它是一種基於單向數據流思想來解決React中事件處理問題的設計模式(不是一個框架)。

我假設你已經對Flux有所瞭解了,因此本文不會具體地去討論Flux。假如你對Flux並不瞭解,可以參考下面兩篇文章:

  1. 使用React和Flux來構建一個記事APP
  2. Flux:一種爲React打造的應用程序架構

Flux將React生態系統帶到了一個更高的層級。即使這樣,當開發者開始使用並熟悉Flux時,一些新的問題又出現了。Flux適合用於管理作爲應用程序狀態的數據,但是如何將初始狀態傳遞進應用程序成爲了又一個問題之源。

圍繞着Flux的數據初始化面臨着許多的挑戰。在Store中向服務器發起請求並傳遞給自身?在dispatcher中使用rehydrate方法? 在服務器上調用一組actions來傳遞到store?對於同構應用而言,如何在返回響應前完成數據的異步加載?

什麼是Relay

Relay是Facebook發佈的一個全新的React數據獲取框架。 Relay致力於爲所有上述這些數據獲取問題提供清晰的解決方案。

Relay主要有以下幾個特點:

  • 描述性 Declarative:這也是React的主要特點之一,對於數據依賴,Relay使用了描述性的代碼風格定義, 這非常類似於在React中定義視圖層組件的方式。這也是和傳統的命令式的數據獲取API主要不同的地方。
  • 託管 Colocation:數據依賴的定義始終伴隨着組件的定義。這使得能夠非常簡單的推出UI組件需要渲染哪些數據。 這使得解決項目中的代碼問題變得非常簡單。只需檢查一個文件中包含的React組件定義,就能立刻知道函數所需要的數據是什麼。
  • 變種 Mutations:它使得無縫的數據修改稱爲可能,也就是說React視圖層會訂閱數據,並且能夠會將修改傳播到數據持久化層。

Relay vs Flux

Flux是一個抽象的概念,而Relay是基於這個抽象概念的實現。Relay是建立在Flux的概念基礎上, 因此也有和Flux中相同的概念,例如dispatcher,actions和stores,但它們代表的含義有所不同。 Relay有一個新的叫做“高階組件”的概念,我們在本文的後面會繼續討論這個概念。

到現階段爲此,還不清楚Relay是否會替代(或並存)現存的Flux實現。 例如,Redux,它是一個非常流行的Flux實現, 同樣也使用了“高階組件”的概念。如果你嘗試同時使用Redux和Relay,會遇到具體由哪個框架綁定到UI組件上的衝突。 目前,你可以參與Redux和Relay關係的討論

高階組件

高級組件(Higher Order Compoenents, 簡稱HOC)的定義採用和普通的React組件相同的方式。 HOC組件會包裹將UI組件作爲孩子包裹起來(稱UI組件爲子UI組件)。HOC組件會執行相關查詢, 然後渲染子UI組件,並將查詢數據作爲props傳遞進UI組件。

現在Flux數據流由HOC組件管理,之後將會扮演dispatcher的角色。它具有一個類似於setQueryParams()的方法, 可以將其看作爲Flux中的action。調用setQueryParams()將會觸發Flux數據流。 定義在HOC組件中的查詢被更新,新的數據被獲取,並被持久化在HOC組件中。 通過持久化這些數據HOC組件也扮演者Flux中Store的角色。

下面來舉個簡單的例子來說明上面的描述:假設有一個ProfilePicture組件和一個對應的HOC組件。 其中ProfilePicture組件可以用來在我們的整個項目中渲染用戶的頭像。相應的,我們需要獲取數據來展示用戶頭像。 因此我們可以藉助Relay來創建一個HOC組件用於從數據庫中查詢用戶的頭像信息。 最後,由HOC組件將數據傳遞給子UI組件(即ProfilePicture組件)。

  1. class ProfilePicture extends React.Component {  
  2.     // A standard Profile Picture component   
  3. }  
  4.   
  5. // HOC: it fetches the data to pass as props to ProfilePicture  
  6. module.exports = Relay.createContainer(ProfilePicture, {  
  7.     fragment: {  
  8.         user: () => Realy.QL `  
  9.             fragment on User {  
  10.                 profilePicture(size: $size) {  
  11.                     uri,      
  12.                 },    
  13.             }  
  14.         `,  
  15.     }  
  16. });  

然後,我們的ProfilePicture組件會通過傳遞進來的props獲得一些新的本地函數。 這就是Relay如何觸發Flux數據流的基本原理。組件調用這些Relay的prop函數,就類似於調用Flux的action。 這可以讓Relay去獲取最新請求的數據,一旦數據獲取完成便將其內部的store作爲Props傳遞給HOC組件的子視圖組件。

GraphQL

上面的代碼中可能有一部分比較陌生的地方,尤其是這部分代碼:

  1. Relay.QL`  
  2.     fragment on User {  
  3.         profilePicture(size: $size) {  
  4.         uri,  
  5.         },  
  6.     }  
  7.     `,  

在Relay背後絕大部分神奇的地方都是由GraphQL驅動的。GraphQL是Facebook開發的一種全新的的查詢語言, 尤其擅長於查詢圖結構的數據。深入的討論GraphQL不屬於本文的範疇,你可以參考以下幾篇文章來了解GraphQL:

  1. Relay和GraphQL簡介
  2. Relay入門

現有的項目並不能直接與GraphQL集成,需要做相關的配置工作。首先你需要做的是:

  1. 創建GraphQL的Schema。
  2. 創建一個GraphQL服務器。

值得考慮的的是,對於已有的項目,如果想要改造項目以使用GraphQL模式可能會涉及到大量的修改工作, 你需要將現有服務器配置並修改爲GraphQL友好的。因此,推薦你在啓動一個新項目時嘗試使用Relay, 爲此,Facebook還提供了一個Relay Starter Kit來幫助你快速的使用Relay和GraphQL啓動一個新的項目。

沒有GraphQL的Relay

由於設置GraphQL涉及到一些額外工作,因此Relay並不適合在現有項目中使用。幸運的是,受到Relay的啓發, 有一個叫做react-transmit的庫可以更好的適應現有項目。它是一個開源項目, 其宣傳語就是“一個受Relay啓發的,使用Promise代替GraphQL的開源庫”。

我們可以用react-transmit來重寫上面的例子,代碼如下:

  1. // Import Transmit  
  2. import Transmit from "react-transmit";  
  3.   
  4. class ProfilePicture extends React.Component {  
  5.     // A standard Profile Picture component  
  6. }  
  7.   
  8. // This is our Higher Order Component. It fetches the data to pass  
  9. // as props to Profile Picture  
  10. Transmit.createContainer(ProfilePicture, {  
  11.     fragments: {  
  12.         user: (userId) => {  
  13.             return new Promise(function(resolve, reject) {   
  14.                 // Do some Ajax here and resolve the promise  
  15.             });  
  16.         }  
  17.     },  
  18. });  

使用react-transmit的例子看起來和Relay的例子非常的像。但是,代碼中的user部分現在返回的是Promise,而不是GraphQL查詢。

Relay的近況

Facebook已經發布並開源了Relay的技術預覽版。 在它的代碼庫中有一些非常不錯的例子展示瞭如何使用Relay,並且有一個非常詳盡的文檔

此刻對於Relay是否適合同構App還沒有定論,因爲暫時還沒有方法能夠告訴Relay,讓它在渲染子視圖之前, 先等待所有的數據依賴被加載完成,因此在服務器端需要做些事情。加入你對這個話題感興趣,你可以參與有關Relay如何在服務端工作的討論。 在問題還沒有解決之前,你可以嘗試使用react-transmit來應對相關問題。

至於Relay的未來,它的路線圖展示了它未來的幾個關鍵特性:

  • 適用於其他存儲類型的是配置,不僅僅是圖結構的數據。
  • 更好的同構支持,正如前面所提到的。

總結

在本文中,我們討論一個新的被稱爲Relay的React附屬框架。React基於和Flux同樣的概念而構建, 並且由GraphQL驅動。正如我提到的,Relay可能並不適合用於一些現有項目。但是,這個框架非常的新, 期望它能夠有越來越好的版本發佈。

原文鏈接:React Data Fetching with Relay

http://www.csdn.net/article/1970-01-01/2825885

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章