При использовании клиентской схемы с пользовательским обработчиком-провайдером все идет хорошо, я могу установить некоторые начальные значения на стороне сервера, и они отображаются в пользовательском интерфейсе. Но при использовании commitLocalUpdate значения не обновляются в пользовательском интерфейсе ...
При использовании стандартного обработчика-провайдера они все же обновляются. А мой пользовательский обработчик - это копия ViewerHandler реле!
Что я пропустил?
Пример:
Разница с примером:
- В примере используется пользовательский обработчик для поля внутри фрагмента в Query
title @__clientField(handle: "draft")
, см. Здесь на github . Я пытаюсь использовать его в пользовательском типе ClientState в запросе.
Реле по умолчанию:
handlerProvider
: предоставляет обработчики по умолчанию для среды
Viewer
: тип по умолчанию, определенный в схеме по умолчанию
ViewerHandler
: это обработчик для типа Viewer
Особенности и настройки приложения:
handlerProvider
: пользовательская версия с дополнительным обработчиком
ClientState
: дополнительный тип, который я хотел бы использовать
ClientStateHandler
: пользовательский обработчик, который является копией реле ViewerHandler
- Я создал clientSchema.graphql в
src/
моего проекта, который компилируется реле-компилятором без каких-либо дополнительных настроек.
Этот запрос работает должным образом со стандартным ViewerHandler.
const Comp_Relay = withData(Comp, {
query: graphql`
query Comp_Query {
clientState @__clientField(handle: "clientState") {
isEditor_locked
}
viewer {
user {
role
}
}
}
`
});
Когда я передаю пользовательский handlerProvider для использования ClientStateHandler, все идет хорошо, и я не получаю сообщение об ошибке. Исходные данные (isEditor_locked: true) установлены правильно. Но обновление интерфейса кажется невозможным.
Примечание: я использую Next.js -> SSR, который происходит здесь.
Гипотеза:
- Может ли быть связано с тем, что тип ClientState выглядит как тип Circular?
- Кажется, все работает на стороне сервера, но не на стороне клиента ...
- Должен ли я где-нибудь промыть магазин? Использовать апдейтер?
-
@__clientField
не предназначен для такого использования?
Это обновление, сделанное клиентом с помощью onClick.
commitLocalUpdate(this.props.environment, store => {
let s = store.get(this.props.clientState.id);
s.setValue(false, 'isEditor_locked');
});
Вот файл client.graphql в src /:
extend type ClientState {
isEditor_locked: Boolean
}
Создание среды (содержит пользовательский обработчик Provider, см. Далее ниже)
relayEnvironment = new Environment({
handlerProvider,
network,
store
});
Пользовательский обработчик Provider
import { ConnectionHandler, ViewerHandler } from 'relay-runtime';
const handlerProvider = handle => {
switch (handle) {
case 'connection':
return ConnectionHandler;
case 'viewer':
return ViewerHandler;
case 'clientState':
return ClientStateHandler;
}
throw new Error(`Unknown handle ${handle}`);
};
и, наконец, пользовательский обработчик (копия ViewerHandler из relay-runtime):
import { ROOT_ID } from 'relay-runtime';
const PREFIX = 'client:';
function generateRelayClientID(id, storageKey, index) {
let key = id + ':' + storageKey;
if (index != null) {
key += ':' + index;
}
if (key.indexOf(PREFIX) !== 0) {
key = PREFIX + key;
}
return key;
}
const VIEWER_ID = generateRelayClientID(ROOT_ID, 'clientState');
const VIEWER_TYPE = 'Viewer';
const ClientStateHandler = {
update: function update(store, payload) {
const record = store.get(payload.dataID);
if (!record) {
return;
}
const serverViewer = record.getLinkedRecord(payload.fieldKey);
if (!serverViewer) {
// If `serverViewer` is null, `viewer` key for `client:root` should already
// be null, so no need to `setValue` again.
return;
}
// Server data already has viewer data at `client:root:viewer`, so link the
// handle field to the server viewer record.
if (serverViewer.getDataID() === VIEWER_ID) {
record.setValue(null, payload.fieldKey);
record.setLinkedRecord(serverViewer, payload.handleKey);
return;
}
// Other ways to access viewer such as mutations may have a different id for
// viewer: synthesize a record at the canonical viewer id, copy its fields
// from the server record, and delete the server record link to speed up GC.
const clientViewer = store.get(VIEWER_ID) || store.create(VIEWER_ID, VIEWER_TYPE);
serverViewer.setValue(true, 'isEditor_locked');
clientViewer.copyFieldsFrom(serverViewer);
record.setValue(null, payload.fieldKey);
record.setLinkedRecord(clientViewer, payload.handleKey);
// Whatever the value you set for payload.handleKey is what the React component will see.
// Make sure the root object points to the viewer object as well
const root = store.getRoot();
root.setLinkedRecord(clientViewer, payload.handleKey);
},
VIEWER_ID
};