当使用带有自定义handlerProvider的客户端架构时,一切都进行得很好,我可以在服务器端设置一些初始值,它们会显示在UI中。但是当使用commitLocalUpdate时,值不会在UI中更新...
但是使用默认的handlerProvider,它们确实会更新。我的自定义处理程序是中继的ViewerHandler的副本!
我想念什么?
示例:
与示例不同:
title @__clientField(handle: "draft")
see here on github上一个片段内的字段。我正在尝试在查询中的自定义类型ClientState上使用它。默认中继:
handlerProvider
:为环境提供默认处理程序Viewer
:默认情况下在架构中定义的默认类型ViewerHandler
:是Viewer类型的处理程序应用细节和自定义设置:
handlerProvider
:具有附加处理程序的自定义版本ClientState
:我要使用的另一种类型ClientStateHandler
:一个自定义处理程序,它是中继站ViewerHandler
的副本src/
中创建了一个clientSchema.graphql,它是由中继编译器编译的,没有任何其他配置。此查询可与默认的ViewerHandler一起正常工作。
const Comp_Relay = withData(Comp, {
query: graphql`
query Comp_Query {
clientState @__clientField(handle: "clientState") {
isEditor_locked
}
viewer {
user {
role
}
}
}
`
});
当我通过自定义处理程序提供程序以使用ClientStateHandler时,一切进展顺利,并且未收到任何错误消息。初始数据(isEditor_locked:true)设置正确。但是UI更新似乎是不可能的。
注意:我正在使用Next.js-> SSR进行操作。
假设:
@__clientField
不能这样使用吗?这是客户端通过onClick进行的更新。
commitLocalUpdate(this.props.environment, store => {
let s = store.get(this.props.clientState.id);
s.setValue(false, 'isEditor_locked');
});
这是src /中的client.graphql:
extend type ClientState {
isEditor_locked: Boolean
}
环境创建(包含一个自定义的handlerProvider,请参见下文)
relayEnvironment = new Environment({
handlerProvider,
network,
store
});
自定义handlerProvider
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的副本):
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
};