即時欄位
客戶端狀態與伺服器狀態之間的一個關鍵差異在於,隨著時間推移,客戶端狀態的變更將需要在您的 UI 中反映出來。為了處理這個問題,Relay 解析器支援將其標記為 @live
的功能。即時解析器預期會回傳一個 LiveState
造型的物件,其中包含允許 Relay read()
當前值以及 subscribe()
訂閱值變更的方法。
隨著此值隨時間變更,Relay 會自動重新計算任何依賴此欄位的衍生欄位 (包括變更串連時的遞移相依性),並有效率地觸發任何元件/訂閱者的更新,這些元件/訂閱者已讀取因變更而更新的欄位。
@live
- Docblock
若要將解析器標記為即時,請將 @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;