具有自定义handlerProvider的客户端架构-值不会更新

时间:2018-08-27 16:31:13

标签: relayjs next.js

当使用带有自定义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进行操作。

假设:

  • 是否可能与ClientState类型看起来是Circular类型这一事实有关?
  • 这一切似乎都可以在服务器端运行,而不能在客户端上运行...
  • 我应该在某处冲洗商店吗?使用更新程序?
  • @__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
};

0 个答案:

没有答案