突变后如何更新分页列表?

mxs*_*tbr 6 javascript apollo graphql react-apollo apollo-client

我有一个带有消息列表的线程,该消息列表是通过GET_THREAD_MESSAGES查询获取的。该查询是分页的,具体取决于用户是否之前看到该线程,可能会加载第一页,最后一页或仅加载新消息。(即first/after/before/last可以使用任何值传递)

thread(id: "asdf") {
  messageConnection(after: $after, first: $first, before: $before, last: $last) {
    edges {
      cursor
      node { ...messageInfo }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

现在我有一个sendMessage突变,我称之为,然后在该update突变的方法中,我想乐观地将发送的消息添加到线程消息中,以获得更好的UX。没有分页,我知道我会这样做:

const data = store.readQuery({
  query: GET_THREAD_MESSAGES,
  variables: { id: message.threadId }
})

data.messageConnection.edges.push(newMessageEdge);

store.writeQuery({
  query: GET_THREAD_MESSAGES,
  variables: { id: message.threadId },
  data,
})
Run Code Online (Sandbox Code Playgroud)

不幸的是,由于我知道有分页,因此该store.readQuery调用会引发一个错误,提示“它找不到该messageConnection线程的字段”,因为该字段现在类似于messageConnection({ after: 'jfds1223asdhfl', first: 50, before: null, last: null })。在阿波罗文档说,你应该用@connection指令的查询工作,解决这一问题。我试图将查询更新为如下所示:

thread(id: "asdf") {
  messageConnection(...) @connection(key: "messageConnection") {
    edges {
      cursor
      node { ...messageInfo }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,当我使用乐观更新被返回并正确显示时,但是一旦服务器返回存储的实际消息,我就会收到一条错误"Missing field cursor in { node: { id: '...', timestamp: '...'"消息,说,因为显然服务器返回的消息不是a MessageConnectionEdge,而是节点,因此没有游标字段。

我怎样才能告诉Apollo仅替换乐观响应的节点,而不是整个边缘?是否有其他方法可以解决原始问题?

mxs*_*tbr 3

唷,我终于解决了这个问题。事实证明,问题根本不在于突变,而在于线程中为新消息并行运行的订阅。(捂脸)

\n\n

TL;DR:如果您在突变发生变化时订阅了相同的数据,请确保在两种更新方法中包含相同的字段!

\n\n

订阅方法如下所示:

\n\n
subscribeToNewMessages: () => {\n  return props.data.subscribeToMore({\n    document: subscribeToNewMessages,\n    variables: {\n      thread: props.ownProps.id,\n    },\n    updateQuery: (prev, { subscriptionData }) => {\n      const newMessage = subscriptionData.data.messageAdded;\n      return Object.assign({}, prev, {\n        ...prev,\n        thread: {\n          ...prev.thread,\n          messageConnection: {\n            ...prev.thread.messageConnection,\n            edges: [\n              ...prev.thread.messageConnection.edges,\n              { node: newMessage, __typename: 'ThreadMessageEdge' },\n            ],\n          },\n        },\n      });\n    },\n  });\n},\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果您眼力好,您会立即发现问题:插入的边缘不提供光标\xe2\x80\x94,这正是 Apollo Client 在警告中告诉我们的!修复方法是将光标添加到插入的边缘:

\n\n
{ node: newMessage, cursor: newMessage.id, __typename: 'ThreadMessageEdge' }\n
Run Code Online (Sandbox Code Playgroud)\n\n

希望这可以帮助其他遇到此警告的人,请确保对订阅和突变update方法进行三次检查!

\n