構建 F8 2016 App 附錄 II 使用 Relay 和 GraphQL
上一篇:構建 F8 2016 App 附錄 I:本地運行 App
在我們最初構建 app 時,我們討論了對數據層的選擇。并將我們最終使用的 Redux 框架與 非死book 的開源框架 Relay 進行了對比。
當時我們選擇了 Redux,是因為與 Relay 相比,Redux 提供了更便捷的數據層實現,且與 Parse 的數據存儲可以更快更容易的結合使用。
F8 的 iOS 和 Android 的應用開發完成上線后。我們再次回顧對數據層的框架選擇,想嘗試在我們的 App 中如何使用 Relay。
緩慢的轉變
在傳統原生 App 的開發中,更換數據層意味著整個應用的推翻重寫,已有的功能都會被全部替換。
React Native 則不同。替換一個獨立的 View 的數據層時,已有的絕大部份數據設置邏輯(Redux, Parse, 和相關的綁定),我們都可以保留。不需要重寫或大量重構,我們可以只把 App 中的某個模塊的數據層替換為新的數據層,其余模塊繼續使用已有數據層。
需要說明的是,這種逐步改善 App 的能力可以極大的降低維護和升級的開銷,對應用的開發非常有利。
那么相比 Redux,使用 Relay 和 GraphQL 如果處理數據層呢?
介紹 Relay 和 GraphQL
首先,簡單的說,Relay 是 app 中的一個數據框架。GraphQL 是 Relay 中表示數據模型的查詢語言。GraphQL 運行在服務器上,與 app 相隔離,給 Relay 提供交互所需要的數據源(我們之后的教程中會介紹 GraphQL 服務器的搭建,敬請期待)。
Relay 不是 Flux 構架的衍生物,且只能和 GraphQL 配合使用。這就直接意味著和 Redux 模型完全徹底不同。我們在數據層教程中已經介紹的 Store/Reducer/Component 交互在 Relay 中是不存在的。它采用一種不一樣的方法,并且移除了你和數據交互時需要做的一些構建工作。
在 Relay 中,各個 React component 具體依賴樣的數據,取決于 GraphQL 的使用。Relay 處理一切有關數據獲取,當數據改變后更新組件,客戶端的數據緩存的事情。當客戶端需要修改數據的時候,創建一個 GraphQL Mutation 而不是像使用 Redux 時創建一個 Action.
F8 App 中的一個的例子
鑒于具有逐漸改變 React Native 應用的一小部分的能力,我們選擇把 F8 app 的 Info View 這個模塊中的 Redux 替換為 Relay,作為一種概念證明.
Info 這個模塊在 app 中和其余模塊幾乎時徹底分離的,而且大量內容都是非交互性的,用這個模塊是最佳選擇。
Info View 中包含一個非常簡單的 <InfoList>
組件:
/* from js/tabs/info/F8InfoView.js */
function InfoList({viewer: {config, faqs, pages}, ...props}) {
return (
<PureListView
renderEmptyList={() => (
<View>
<WiFiDetails
network={config.wifiNetwork}
password={config.wifiPassword}
/>
<CommonQuestions faqs={faqs} />
<LinksList title="非死book pages" links={pages} />
<LinksList title="非死book policies" links={POLICIES_LINKS} />
</View>
)}
{...props}
/>
);
}
這只是包含一些簡單信息展示類組件的基本布局,但組件中的 props
和參數從哪來的呢?哈哈,在這個 js 文件中,我們有一個連接 GraphQL 的 fragment
:
/* from js/tabs/info/F8InfoView.js */
InfoList = Relay.createContainer(InfoList, {
fragments: {
viewer: () => Relay.QL`
fragment on User {
config {
wifiNetwork
wifiPassword
}
faqs {
question
answer
}
pages {
title
url
logo
}
}
`,
},
});
這里,我們用一個 GraphSQL fragment
定義了 <InfoList>
組件需要展示的數據。它和我們在 GraphQL 服務器上定義的 GraphQL 對象是對應的:
/* from server/schema/schema.js */
var F8UserType = new GraphQLObjectType({
name: 'User',
description: 'A person who uses our app',
fields: () => ({
id: globalIdField('User'),
name: {
type: GraphQLString,
},
...
faqs: {
type: new GraphQLList(F8FAQType),
resolve: () => new Parse.Query(FAQ).find(),
},
pages: {
type: new GraphQLList(F8PageType),
resolve: () => new Parse.Query(Page).find(),
},
config: {
type: F8ConfigType,
resolve: () => Parse.Config.get(),
}
}),
...
});
你可以看到數據是如何從 GraphQL 服務器上被獲取的,然后 Relay 開始接手所有需要的且在 fragment
中指定的數據。這時viewer
的參數就可以被 <InfoList>
組件訪問到了,使用了一些 destructuring assignments,反過來構建了在組件中使用的config
, faq
,pages
變量。
歸功于 Relay 的內建邏輯,我們不用擔心數據變化的監聽,或者數據本地儲存等等。我們只需要告訴 Relay 組件中應該有什么數據,然后以標準的 React 方式來設計我們需要的組件。如果 GraphQL 服務器已經搭建好,以上就是我們需要做的所有事情。
我們的 Info View 中沒有數據的變化,然而如果你想了解更多原理,請閱讀在 Relay 在 mutations 上面的文檔。
下一篇:構建 F8 2016 App 附錄 III 將 F8 應用移植到 windows 平臺—使用 React Native開發
來自:pockry