自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

React庫+GraphQL服務(wù)器+Relay架構(gòu)聯(lián)合作戰(zhàn)(上)

譯文
開發(fā) 后端
本系列文章較全面地分析了時下流行的React庫、GraphQL服務(wù)器以及Relay架構(gòu)模式各自的功能特征,并通過一個具體的實例向你展示它們是如何相互配合來完成一款Web應(yīng)用的開發(fā)的。

 【摘要】本系列文章較全面地分析了時下流行的React庫、GraphQL服務(wù)器以及Relay架構(gòu)模式各自的功能特征,并通過一個具體的實例向你展示它們是如何相互配合來完成一款Web應(yīng)用的開發(fā)的。本篇屬于本系列的上篇,側(cè)重于React庫、GraphQL服務(wù)器和Relay架構(gòu)各自功能及其關(guān)系解析。

[[170372]]

概述

不同于如AngularJS和Ember這樣的框架,React是一個客戶端庫,其中提供了一組有限的函數(shù),而且該庫幾乎獨立于構(gòu)建應(yīng)用程序其他功能時所可能需要的其他庫。從根本上說,React提供了客戶端UI組件功能,其中提供了一種機制來創(chuàng)建組件、管理組件中的數(shù)據(jù),渲染組件,以及復(fù)合小組件來構(gòu)建更大的組件。React可以用于多種情景下,無論數(shù)據(jù)來自何處、 如何檢索數(shù)據(jù)或如何把數(shù)據(jù)作為一個更大的應(yīng)用程序的一部分進行管理的。為了有效地對付這些問題,需要利用其他的庫和模式。一個用于React應(yīng)用程序的常見模式是Flux。

人們開發(fā)Flux的目的是把它作為MVC(模型-視圖-控制器)模式的一種替代方法,來管理響應(yīng)動作的數(shù)據(jù)流。與MVC的雙向數(shù)據(jù)流動不同,F(xiàn)lux依賴于系統(tǒng)中的各個部件之間的單向數(shù)據(jù)流。Flux是Facebook創(chuàng)建的,因為他們的開發(fā)人員發(fā)現(xiàn)很難了解采用MVC模式開發(fā)的大型應(yīng)用程序中的數(shù)據(jù)運動規(guī)律。

不同于MVC模式所采用的多環(huán)路數(shù)據(jù)流,F(xiàn)lux使用的是單環(huán)路數(shù)據(jù)流方案。數(shù)據(jù)僅沿著一條線路流動,這條線路是:動作(Action)->調(diào)度器(Dispatcher)->存儲(Store)(或多個存儲)->組件(即視圖)->動作。

其中,動作(Action)表示某種進入系統(tǒng)的事件。這可能是用戶生成的,如請求刷新數(shù)據(jù)的按鈕單擊事件,或者也可能是通過一個Web套接字接收消息事件。然后,這個動作被傳遞給調(diào)度器將它發(fā)送到所有的存儲。調(diào)度器其實只不過是一個轉(zhuǎn)發(fā)機制。它不懂動作是什么,動作所傳遞的數(shù)據(jù)的含義,而也不懂得與該動作相關(guān)的每個存儲的功能。它只是把動作調(diào)度給所有的存儲,然后每個存儲決定是否應(yīng)該處理這一動作。存儲負(fù)責(zé)維護數(shù)據(jù)的本地副本,強制實施業(yè)務(wù)規(guī)則并通知新數(shù)據(jù)的組件,以便能刷新它們。你可以認(rèn)為存儲是維護應(yīng)用程序狀態(tài)的,而整個Flux流程本質(zhì)上就是一個狀態(tài)機。因此,React組件利用了狀態(tài)機模式。在某種意義上,F(xiàn)lux利用與此相同的狀態(tài)機模式來架構(gòu)整個應(yīng)用程序。

雖然Flux是解決數(shù)據(jù)流問題的一種模式,但它本身并沒有提供實現(xiàn)這種模式的技術(shù)。若要使用Flux模式,開發(fā)人員不得不創(chuàng)建系統(tǒng)中所有的組件,除了Facebook提供的調(diào)度器之外。創(chuàng)建一個Flux系統(tǒng)是相對比較容易的,但它需要大量的樣板代碼。在這方面,它面臨與Backbone.js同樣的問題。啟動和運行系統(tǒng)是很容易的,但最終需要大量的編碼。

Flux進化過程

當(dāng)開發(fā)人員使用Flux時,他們開始想辦法來把樣板代碼重構(gòu)到可重用的庫中。此外,他們還能夠確定出Flux中的子模式,這使得對于應(yīng)用程序中數(shù)據(jù)流的分析判斷更為容易,而且還在而不犧牲Flux一般優(yōu)點的情況下減少應(yīng)用程序的復(fù)雜性。這些子模式包括:把應(yīng)用程序中的多存儲減少到一個存儲;把調(diào)度器與存儲結(jié)合到相同的組件(當(dāng)只有一個存儲時這是很重要的)中;而且,還能夠把諸多組件封裝到一個容器中,此容器中可以在黑箱中創(chuàng)建動作、調(diào)度和進行存儲管理。如今,許多Flux的衍生產(chǎn)品不再僅僅局限于純粹的Flux功能,而且還能夠在保留其根本要素的同時避免Flux通常的缺點,即大量的樣板代碼的問題。

目前,雖然有很多Flux的衍生產(chǎn)品,但是Redux是更受歡迎的模式之一。Redux純粹基于狀態(tài)機概念和不可變數(shù)據(jù)的思想而構(gòu)建。在該模式中,動作都由單一的“調(diào)度器-存儲”來處理;這些“調(diào)度器-存儲”對象使用reducer函數(shù)(它們本身是可以組合的)實現(xiàn)把一種狀態(tài)轉(zhuǎn)換到另一種狀態(tài)。這就在極大地簡化Flux模式的同時引進很多函數(shù)編程特征;一旦你徹底掌握這一技術(shù),React應(yīng)用程序編碼將容易許多。

Relay是來自于Facebook團隊的另一個Flux的衍生產(chǎn)品,此模式日漸普及。關(guān)于Facebook如何使用Relay以及其與Flux關(guān)系的處理方案的更多信息,請參考網(wǎng)址https://facebook.github.io/react/blog/2015/02/20/introducing-relay-and-graphql.html

Relay框架功能分析

雖然Redux簡化了應(yīng)用程序的管理,但是在實際數(shù)據(jù)定位方面卻不可知。它可以使用任何數(shù)據(jù)存儲系統(tǒng),但是再一次導(dǎo)致更多的樣板代碼(雖然少于Flux)問題。于是,出現(xiàn)了Relay (這是Facebook創(chuàng)建的另一個產(chǎn)品,其應(yīng)用了其他大量的JavaScript開源產(chǎn)品,例如React,Relay,Immutable.js,GraphQL,Jest,F(xiàn)low等),它的宗旨在于通過重構(gòu)去除數(shù)據(jù)訪問相關(guān)的樣板代碼部分,同時還引進另一種新的數(shù)據(jù)服務(wù)——GraphQL。GraphQL不同于傳統(tǒng)REST服務(wù)的地方在于,它把數(shù)據(jù)視為一個圖形,并力求以分層方式來描述該圖形,從而使數(shù)據(jù)消費者自己指定他們需要的數(shù)據(jù),而不是傳統(tǒng)的REST服務(wù)中那樣提供一組固定的數(shù)據(jù)集服務(wù)而不考慮消費者需求。

那么,Relay到底是做什么的呢?Relay是一個框架,它負(fù)責(zé)把React組件連接到GraphQL服務(wù)器,此連接是通過一個實現(xiàn)了動作、調(diào)度器和存儲的容器實現(xiàn)的。開發(fā)人員不需要對動作、調(diào)度器和存儲進行編程,而可以觸發(fā)這些動作并通過Relay API來訪問相應(yīng)的結(jié)果。若要配置容器,開發(fā)人員必須提供GraphQL查詢和突變片段(mutation fragments)向容器描述數(shù)據(jù)的圖結(jié)構(gòu);此外,Relay還會負(fù)責(zé)照顧數(shù)據(jù)管理的所有細節(jié)。

Relay的確是一個框架(如Angular),而不是一個庫。它的實現(xiàn)可以說是透明的——它需要通過React實現(xiàn)UI組件而且由GraphQL提供數(shù)據(jù)服務(wù)。一旦GraphQL服務(wù)器和React組件配置到位,Relay將接管并執(zhí)行所有需要的操作。因此,使用Relay的關(guān)鍵是掌握配置過程。

此外,與框架Angular(它僅對客戶端有專門需求)不同,Relay還要求GraphQL服務(wù)器接口來為Relay容器提供數(shù)據(jù)查詢和變異操作。但是,只要通過特定的GraphQL接口提供數(shù)據(jù),Relay并不在意如何存儲數(shù)據(jù)。

因此,Relay需要后端和前端兩個開發(fā)團隊都要了解它的工作原理,并要求他們弄清程序的的每個部件(無論前端還是后端)是如何編碼和配置的。

Relay與React的配合

本小節(jié)中,讓我們從React的角度來研究一下Relay。程序員們可以使用多種語言對GraphQL服務(wù)器進行編碼與配置,并部署到多種平臺上。對于Node.js環(huán)境下的GraphQL實現(xiàn)來說,有一個稱為graphql-relay(https://www.npmjs.com/package/graphql-relay)的包可以用于簡化GraphQL服務(wù)器的編碼和配置要求。在React方面,則存在一個名為relay-react(https://www.npmjs.com/package/react-relay)的包可用于配置Relay容器和路由,還能夠激發(fā)動作來實現(xiàn)數(shù)據(jù)變異操作等。

Relay開發(fā)入門

入門Relay是有些難度的。因為該技術(shù)是如此之新而且有很多的競爭對手,所以,有關(guān)如何使用Relay的參考資源目前還相當(dāng)有限。而提供資源的地方,一般提供的例子也是很有限的;為此,開發(fā)人員最終被迫去閱讀博客文章、翻閱GitHub問題和正式的產(chǎn)品說明書才能創(chuàng)建一個簡單的CRUD應(yīng)用程序。此外,還需要搭建一個相當(dāng)復(fù)雜的開發(fā)環(huán)境以及需要有一個正確配置的GraphQL服務(wù)器。因此,這樣的任務(wù)對于JavaScript/前端開發(fā)新手而言可能相當(dāng)艱巨。

作為準(zhǔn)備工作,請首先克隆一下GitHub網(wǎng)站上的存儲倉庫(https://github.com/DevelopIntelligenceBoulder/react-flux-blog)到您的計算機上,并打開相應(yīng)的文件夾blog-post-5+6。此文件夾包含一個完整的GraphQL/React/Relay應(yīng)用程序。為了便該應(yīng)用程序啟動并運行起來,請打開一個終端,導(dǎo)航到文件夾blog-post-5+6中,并運行以下Gulp命令。

  1. $ npm i 
  2.  
  3. $ npm i -g gulp eslint eslint-config-airbnb eslint-plugin-react@^4.3.0 webpack babel-cli babel-eslint eslint-plugin-jsx-a11y@^0.6.2 
  4.  
  5. $ gulp 
  6.  
  7. $ npm run update-schema 
  8.  
  9. $ gulp 
  10.  
  11. $ gulp server 

現(xiàn)在,請打開微軟的Edge瀏覽器(【譯者注】微軟專門為Windows 10配置的高性能瀏覽器),然后導(dǎo)航到下面的URL:http://localhost:3000。

你會注意到,頁面中將顯示一個小控件列表,并使用Bootstrap 4風(fēng)格進行修飾,看起來相當(dāng)漂亮。(【譯者注】因某種原因原文并沒有提供結(jié)果快照)

該項目的基本開發(fā)構(gòu)架是典型的文件夾組織方式。其中,src文件夾中存放可編輯的源代碼文件,而最終的部署文件夾是dist(源代碼文件都要復(fù)制至此處),應(yīng)用程序正是使用此處的文件執(zhí)行的。復(fù)制過程是使用Gulp命令進行的;具體地說,是通過組合一些簡單的復(fù)制文件命令、創(chuàng)建一個處理SASS文件的任務(wù),還有一個針對JavaScript的Web打***程完成的。其中,Web打包處理機制使用Babel轉(zhuǎn)譯器把RelayQL、JSX和ES2015代碼轉(zhuǎn)換為 ES5.1兼容的可以在任何瀏覽器中執(zhí)行的JavaScript代碼。ES2015和JSX轉(zhuǎn)譯已經(jīng)不是什么新技術(shù),但對于RelayQL的轉(zhuǎn)譯卻是一個新課題。

RelayQL與Babel-Relay插件

GraphQL服務(wù)器能夠通過使用內(nèi)省(introspection)機制自動生成結(jié)構(gòu)(【譯者注】原文中用詞是schema,這個詞在數(shù)據(jù)庫表格設(shè)計中常用;而其他許多軟件技術(shù)中也廣泛使用這個詞,而且經(jīng)常譯為“模式”或“架構(gòu)”。為了區(qū)別本文中另兩個詞pattern和architecture,在此特意譯為“結(jié)構(gòu)”)。結(jié)構(gòu)(schema)其實是一個JSON文件,其中描述的所有類型由特定的GraphQL服務(wù)器使用。結(jié)構(gòu)中可以包含自定義和內(nèi)置類型。Babel-Relay插件使用此結(jié)構(gòu)來校驗使用RelayQL編碼形成的GraphQL片段(fragments)。這些片段是使用ES2015字符串模板編碼的,一旦它們通過根據(jù)結(jié)構(gòu)定義的校驗就被轉(zhuǎn)換為JavaScript代碼。這種校驗可以有效地防止 GraphQL錯誤的發(fā)生。

配置Babel-Relay插件也是生成結(jié)構(gòu)(schema)最簡單的方法是,直接使用從Relay網(wǎng)站(https://facebook.github.io/relay/docs/guides-babel-plugin.html)或Relay初學(xué)者工具包項目(https://github.com/relayjs/relay-starter-kit)中下載的例子。這些文件正是本文對應(yīng)的Github存儲庫中所使用的,并遵從Relay官網(wǎng)上推薦的開發(fā)模式。

從Relay初學(xué)者工具包項目中,我們需要使用兩個文件:build/babelRelayPlugin.js和scripts/updateSchema.js。其中,UpdateSchema.js文件將用于生成結(jié)構(gòu)(schema),而babelRelayPlugin.js文件將使用結(jié)構(gòu)文件來校驗證GraphQL片段以及轉(zhuǎn)換RelayQL代碼。

GraphQL與Relay協(xié)作

通常情況下,要使用Relay需要修改標(biāo)準(zhǔn)的GraphQL服務(wù)器實現(xiàn)方案。我們可以使用一個名為graphql-relay(https://www.npmjs.com/package/graphql-relay)的包來幫助把基于Node.js的GraphQL服務(wù)器配置為Relay兼容型的。要配置成一個Relay特定類型的GraphQL服務(wù)器需要三個主要方面:對象標(biāo)記(Object Identification)、類型連接(Type Connections)和突變(Mutations)。

通過使用一個全局唯一的ID值,對象標(biāo)記允許Relay從GraphQL服務(wù)器查詢實現(xiàn)了節(jié)點接口的任何類型。這個全局ID是base64編碼的,其中包含類型名稱和一個后面跟一個冒號的本地ID值。graphql-relay庫提供了分別命名為toGlobalID和fromGlobalID的函數(shù)支持在全局 ID之間來回轉(zhuǎn)換。另外,類型名稱來自于在類型配置中指定的GraphQL自定義類型名稱。通常情況下,本地ID值來自于數(shù)據(jù)存儲機制,例如關(guān)系數(shù)據(jù)庫中的標(biāo)記(Identity)。請參考下面的代碼:

  1. import { nodeInterface } from './../node-definitions'
  2.  
  3. export const widgetType = new GraphQLObjectType({ 
  4.  
  5. name'Widget'
  6.  
  7. description: 'A widget object'
  8.  
  9. fields: () => ({ 
  10.  
  11. id: globalIdField('Widget'), 
  12.  
  13. // more fields 
  14.  
  15. }), 
  16.  
  17. interfaces: () => [nodeInterface] 
  18.  
  19. }); 

在上面代碼中,文件node-definitions.js(及其相關(guān)文件type-registry)的作用是:為通過節(jié)點接口使對象可用而提供配置與類型注冊。

第二個Relay特定的配置,即類型連接(Type Connections),是建立父類型及其子類型之間的一對多關(guān)系的連接。這些連接是使用一種特殊的連接類型結(jié)構(gòu)管理的。這些特殊的連接類型結(jié)構(gòu)支持圖中的邊緣(graph edge)概念和游標(biāo)(cursor)的概念,用于限制結(jié)果集與生成結(jié)果頁面。可以配置連接和邊緣類型以支持如元數(shù)據(jù)這樣的附加屬性,從而允許控制連接或邊緣特性(例如加權(quán)的邊緣等)。請參考下面的代碼:

  1. import { widgetType } from './types/widget-type'
  2.  
  3. import { connectionDefinitions } from 'graphql-relay'
  4.  
  5. export const { connectionType: widgetConnection, edgeType: WidgetEdge } = 
  6.  
  7. connectionDefinitions({name'Widget', nodeType: widgetType}); 

上面代碼中的ConnectionDefinitions函數(shù)用于創(chuàng)建Relay期望的結(jié)構(gòu)中的連接類型。請參考下面的代碼:

  1. import { widgetConnection } from '../connections/widget-connection'
  2.  
  3. // inside of fields function of viewer type declaration 
  4.  
  5. widgets: { 
  6.  
  7. type: widgetConnection, 
  8.  
  9. description: 'A list of widgets'
  10.  
  11. args: connectionArgs, 
  12.  
  13. resolve: (_, args) => connectionFromPromisedArray(getWidgets(), args) 
  14.  

上面代碼中,WidgetConnection類型是從widget-connection.js文件中導(dǎo)入的,用于配置查看器類型中的控件字段。包graphql-relay中還提供了一個名為connectionArgs的對象,該對象中包含通過Relay傳遞進來的用于處理連接的標(biāo)準(zhǔn)參數(shù)。這些參數(shù)包含的值用于游標(biāo)操作。

第三和***一個Relay特定的配置是突變(mutation)配置。graphql-relay包中提供了一個專門的命名為mutationWithClientMutationId的幫助方法用于簡化突變配置。有四個字段是必需的:突變名稱、輸入字段、輸出字段和獲取有效載荷的字段。在GraphQL中,所有的突變都將伴隨一個查詢來獲知任何數(shù)據(jù)可能已被更改。Relay通過智能地決定突變后需要刷新哪些數(shù)據(jù)來進一步擴展了這種能力。

突變的名字是當(dāng)React-Relay應(yīng)用程序訪問GraphQL服務(wù)器時用來調(diào)用突變的名字。輸入字段對應(yīng)于GraphQL中突變的args參數(shù)。輸出字段描述了要從突變返回的類型的字段。***一個獲取有效載荷的字段將執(zhí)行實際的數(shù)據(jù)庫操作并返回一個promise對象,該對象將推遲從GraphQL到應(yīng)用程序的響應(yīng)時間,直到該promise被解析結(jié)束為止。

小結(jié)

React和GraphQL聯(lián)手,并輔助以Relay,將為構(gòu)建Web應(yīng)用程序提供一個很有前途的框架。雖然開發(fā)過程中需要不少的安裝及配置工作,但是一旦這些工作完畢,開發(fā)過程將流暢地進行下去,消除了樣板代碼,并智能地處理數(shù)據(jù)管理問題。實踐將會證明Relay框架很可能會成為構(gòu)建下一代Web應(yīng)用程序的游戲規(guī)則改變者。在本系列下篇文章中,我們將探討使用React并配合以Relay來控制GraphQL資源的問題。

責(zé)任編輯:趙立京 來源: 51CTO
相關(guān)推薦

2022-07-13 11:16:06

BCS2022網(wǎng)絡(luò)安全

2021-11-22 05:50:26

云計算云計算環(huán)境云應(yīng)用

2022-03-24 10:15:39

PingCAPTiDB數(shù)據(jù)庫

2020-09-30 08:46:12

智能

2024-06-11 00:00:01

用ReactGraphQLCRUD

2010-05-19 10:31:07

IIS服務(wù)器

2018-05-18 09:43:37

服務(wù)器架構(gòu)大型網(wǎng)站

2014-09-22 09:52:06

2009-01-09 22:45:21

2022-04-28 11:19:13

WebRTC服務(wù)器架構(gòu)

2011-01-13 10:01:27

2022-02-17 11:08:46

技嘉科技Canonical服務(wù)器

2024-01-19 11:57:42

2016-08-17 22:36:33

華為華為服務(wù)器服務(wù)器

2018-03-27 17:33:31

服務(wù)器

2019-12-24 14:42:51

Nginx服務(wù)器架構(gòu)

2019-01-10 11:12:15

Nginx服務(wù)器架構(gòu)

2020-05-12 21:17:18

Nginx服務(wù)器架構(gòu)

2019-09-10 15:22:17

Nginx服務(wù)器架構(gòu)

2009-02-18 13:43:00

點贊
收藏

51CTO技術(shù)棧公眾號