構建 F8 2016 App 附錄 II 使用 Relay 和 GraphQL

ywcsz 8年前發布 | 32K 次閱讀 ReactNative 移動開發

上一篇:構建 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 view of F8 iOS app

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, faqpages 變量。

歸功于 Relay 的內建邏輯,我們不用擔心數據變化的監聽,或者數據本地儲存等等。我們只需要告訴 Relay 組件中應該有什么數據,然后以標準的 React 方式來設計我們需要的組件。如果 GraphQL 服務器已經搭建好,以上就是我們需要做的所有事情。

我們的 Info View 中沒有數據的變化,然而如果你想了解更多原理,請閱讀在 Relay 在 mutations 上面的文檔

下一篇:構建 F8 2016 App 附錄 III 將 F8 應用移植到 windows 平臺—使用 React Native開發

來自:pockry

 本文由用戶 ywcsz 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!