跳至主要內容
版本:v18.0.0

即時欄位

客戶端狀態與伺服器狀態之間的一個關鍵差異在於,隨著時間推移,客戶端狀態的變更將需要在您的 UI 中反映出來。為了處理這個問題,Relay 解析器支援將其標記為 @live 的功能。即時解析器預期會回傳一個 LiveState 造型的物件,其中包含允許 Relay read() 當前值以及 subscribe() 訂閱值變更的方法。

隨著此值隨時間變更,Relay 會自動重新計算任何依賴此欄位的衍生欄位 (包括變更串連時的遞移相依性),並有效率地觸發任何元件/訂閱者的更新,這些元件/訂閱者已讀取因變更而更新的欄位。

@live

若要將解析器標記為即時,請將 @live docblock 標籤新增至解析器定義。例如

import type { LiveState } from 'relay-runtime';

/**
* @RelayResolver Query.counter: Int
* @live
*/
export function counter(): LiveState<number> {
return {
read: () => store.getState().counter,
subscribe: (callback) => {
return store.subscribe(callback);
},
};
}
注意

欄位解析器和強模型解析器 (將 ID 對應至模型的解析器) 都可以註解為 @live

LiveState 類型

即時解析器的回傳類型稱為 LiveState。如果您熟悉 observable 或 signal 的概念,則概念上與它們相似。與 observable 不同,當 LiveState 通知訂閱者更新時,它不包含新值。相反地,訂閱者 (Relay) 應呼叫 read() 以取得新值。

雖然支援過度通知 (當讀取值實際上沒有變更時的訂閱通知),但為了效能考量,建議 LiveState 值的提供者在通知 Relay 變更之前,確認值是否確實已變更。

LiveState 的類型定義如下

export type LiveState<T> = {
/**
* Returns the current value of the live state.
*/
read(): T,
/**
* Subscribes to changes in the live state. The state provider should
* call the callback when the value of the live state changes.
*/
subscribe(cb: () => void): () => void,
};

建立 LiveState 物件

在大多數情況下,您會想要定義一個 helper 函式,讀取您的反應式資料儲存區並回傳 LiveState 物件。例如,對於 Redux 儲存區,您可以撰寫一個包裝函式,針對給定的選取器公開 LiveState

type Selector<T> = (state: State) => T;

function selectorAsLiveState<T>(selector: Selector<T>): LiveState<T> {
let currentValue = selector(store.getState());
return {
read: () => currentValue,
subscribe: (cb) => {
return store.subscribe(() => {
const newValue = selector(store.getState());
if (newValue === currentValue) {
return;
}
currentValue = newValue;
cb();
});
return unsubscribe;
},
};
}

使用此 helper 的即時解析器可能如下所示

/**
* @RelayResolver Query.counter: Int
* @live
*/
export function counter(): LiveState<number> {
return selectorAsLiveState(getCounter);
}

function getCounter(state) {
return state.counter;
}

批次處理

當資料層中的狀態變更時,一個變更可能會導致通知許多關於更新的 @live 解析器訂閱。依預設,每個更新都會需要 Relay 執行工作以判斷哪些元件需要更新。這可能會導致執行大量重複的工作。

在可能的情況下,建議您將更新批次處理至 @live 解析器。這可以透過在您的 RelayStore 執行個體上呼叫 batchLiveStateUpdates() 來包裝您的狀態更新來完成。

使用 Redux 儲存區的典型用法可能如下所示

const store = createStore(reducer);
const originalDispatch = store.dispatch;

function wrapped(action) {
relayStore.batchLiveStateUpdates(() => {
originalDispatch(action);
})
}

store.dispatch = wrapped;