GraphQL 訂閱
GraphQL 訂閱是一種機制,可讓客戶端查詢資料以回應伺服器端事件的串流。
GraphQL 訂閱看起來非常類似查詢,只是它使用 subscription
關鍵字
subscription FeedbackLikeSubscription($input: FeedbackLikeSubscribeData!) {
feedback_like_subscribe(data: $input) {
feedback {
like_count
}
}
}
- 使用此 GraphQL 片段建立訂閱,將導致應用程式在
feedback_like_subscribe
串流發出事件時收到通知。 feedback_like_subscribe
是訂閱根欄位(或簡稱訂閱欄位),它會在後端設定訂閱。
- 與變更類似,訂閱分兩個獨立步驟處理。首先,發生伺服器端事件。然後,執行查詢。
請注意,事件串流可以是完全任意的,並且可能與所選欄位沒有關係。換句話說,無法保證在通知之間所選的數值會有所變更。
feedback_like_subscribe
會傳回特定的 GraphQL 類型,該類型會公開我們可以查詢以回應伺服器端事件的資料。在這種情況下,我們正在查詢 Feedback 物件及其更新後的like_count
。這可讓我們即時顯示按讚數。
客戶端收到的訂閱酬載範例可能如下所示
{
"feedback_like_subscribe": {
"feedback": {
"id": "feedback-id",
"like_count": 321,
}
}
}
在 Relay 中,我們也可以使用 graphql
標籤宣告 GraphQL 訂閱
const {graphql} = require('react-relay');
const feedbackLikeSubscription = graphql`
subscription FeedbackLikeSubscription($input: FeedbackLikeSubscribeData!) {
feedback_like_subscribe(data: $input) {
feedback {
like_count
}
}
}
`;
- 請注意,訂閱也可以像查詢或片段一樣參考 GraphQL 變數。
使用 useSubscription
建立訂閱
為了在 Relay 中建立訂閱,我們可以使用 useSubscription
和 requestSubscription
API。讓我們看看使用 useSubscription
API 的範例
import type {Environment} from 'react-relay';
import type {FeedbackLikeSubscribeData} from 'FeedbackLikeSubscription.graphql';
const {graphql, useSubscription} = require('react-relay');
const {useMemo} = require('React');
function useFeedbackSubscription(
input: FeedbackLikeSubscribeData,
) {
const config = useMemo(() => ({
subscription: graphql`
subscription FeedbackLikeSubscription(
$input: FeedbackLikeSubscribeData!
) {
feedback_like_subscribe(data: $input) {
feedback {
like_count
}
}
}
`,
variables: {input},
}), [input]);
return useSubscription(config);
}
讓我們分析一下這裡發生的事情。
useSubscription
採用GraphQLSubscriptionConfig
物件,其中包含以下欄位subscription
:包含訂閱的 GraphQL 文字,以及variables
:用來建立訂閱的變數。
- 此外,
useSubscription
接受 Flow 類型參數。與查詢一樣,訂閱的 Flow 類型是從 Relay 編譯器產生的檔案匯出的。- 如果提供此類型,
GraphQLSubscriptionConfig
也會變成靜態類型。最佳做法是一律提供此類型。
- 如果提供此類型,
- 現在,當
useFeedbackSubscription
hook 提交時,Relay 將建立訂閱。- 與
useLazyLoadQuery
等 API 不同,Relay 在轉譯階段中不會嘗試建立此訂閱。
- 與
- 一旦建立訂閱,每當發生事件時,後端將選取更新後的 Feedback 物件,並從中選取
like_count
欄位。- 由於
Feedback
類型包含id
欄位,Relay 編譯器將自動新增id
欄位的選取。
- 由於
- 收到訂閱回應時,Relay 會在商店中找到具有相符
id
的 feedback 物件,並使用新收到的like_count
值進行更新。 - 如果這些值因此而變更,則選取 feedback 物件上這些欄位的任何元件都會重新轉譯。或者,通俗地說,任何依賴更新資料的元件都會重新轉譯。
參數 FeedbackLikeSubscribeData
的類型名稱衍生自最上層變更欄位的名稱,即 feedback_like_subscribe
。此類型也會從產生的 graphql.js
檔案匯出。
傳遞至 useSubscription
的 GraphQLSubscriptionConfig
物件應進行記憶化!否則,useSubscription
將會處置訂閱,並在每次轉譯時重新建立!
回應訂閱事件重新整理元件
在先前的範例中,我們手動選取了 like_count
。如果我們收到更新的值,選取此欄位的元件將會重新轉譯。
但是,一般而言,最好散布對應於我們想要回應變更而重新整理的元件的片段。這是因為元件選取的資料可能會變更。
要求開發人員知道所有可能會擷取其元件資料的訂閱(並保持最新狀態)是 Relay 想要避免要求的全域推理類型範例。
例如,我們可能會將訂閱重新撰寫如下
subscription FeedbackLikeSubscription($input: FeedbackLikeSubscribeData!) {
feedback_like_subscribe(data: $input) {
feedback {
...FeedbackDisplay_feedback
...FeedbackDetail_feedback
}
}
}
現在,每當發生 feedback_like_subscribe
事件串流中的事件時,FeedbackDisplay
和 FeedbackDetail
元件選取的資料將會重新擷取,而這些元件將保持一致的狀態。
一般來說,散布片段比回應訂閱事件重新擷取資料更好,因為可以在單次往返中擷取更新的資料。
在訂閱觸發、發生錯誤或由伺服器關閉時執行回呼
除了將更新的資料寫入 Relay 商店之外,我們可能還想在收到訂閱酬載時執行回呼。如果收到錯誤,或者如果收到錯誤或伺服器結束訂閱,我們可能想要執行回呼。GraphQLSubscriptionConfig
可以包含下列欄位來處理這些情況
onNext
,在收到訂閱酬載時執行的回呼。它會傳遞訂閱回應(停在片段散布邊界)。onError
,在訂閱發生錯誤時執行的回呼。它會傳遞發生的錯誤。onCompleted
,在伺服器結束訂閱時執行的回呼。
宣告式變更指令
宣告式變更指令和 @deleteRecord
也適用於訂閱。
回應訂閱事件操控連線
Relay 可讓您輕鬆回應訂閱事件,方法是在連線(即清單)中新增或移除項目。例如,您可能想要將新建立的使用者附加至指定的連線。如需詳細資訊,請參閱使用宣告式指令。
回應變更刪除項目
此外,您可能想要回應變更而從商店中刪除項目。為了執行此操作,您會將 @deleteRecord
指令新增至已刪除的 ID。例如
subscription DeletePostSubscription($input: DeletePostSubscribeData!) {
delete_post_subscribe(data: $input) {
deleted_post {
id @deleteRecord
}
}
}
命令式修改本機資料
有時,您想要執行的更新比僅更新欄位的值更複雜,並且無法由宣告式變更指令處理。對於這種情況,GraphQLSubscriptionConfig
接受 updater
函式,可讓您完全控制如何更新商店。
這在命令式更新商店資料一節中會詳細討論。
設定網路層
您需要設定您的網路層來處理訂閱。
通常,GraphQL 訂閱是透過WebSockets進行通訊,以下是使用graphql-ws的範例
import {
...
Network,
Observable
} from 'relay-runtime';
import { createClient } from 'graphql-ws';
const wsClient = createClient({
url:'ws://localhost:3000',
});
const subscribe = (operation, variables) => {
return Observable.create((sink) => {
return wsClient.subscribe(
{
operationName: operation.name,
query: operation.text,
variables,
},
sink,
);
});
}
const network = Network.create(fetchQuery, subscribe);
或者,也可以使用舊版的subscriptions-transport-ws程式庫
import {
...
Network,
Observable
} from 'relay-runtime';
import { SubscriptionClient } from 'subscriptions-transport-ws';
const subscriptionClient = new SubscriptionClient('ws://localhost:3000', {
reconnect: true,
});
const subscribe = (request, variables) => {
const subscribeObservable = subscriptionClient.request({
query: request.text,
operationName: request.name,
variables,
});
// Important: Convert subscriptions-transport-ws observable type to Relay's
return Observable.from(subscribeObservable);
};
const network = Network.create(fetchQuery, subscribe);
此頁面是否實用?
請協助我們讓網站變得更好,方法是 回答幾個快速問題.