首页 文章

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

提问于
浏览
4

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

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

现在我有一个 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,
})

不幸的是,因为我知道有分页, store.readQuery 调用会抛出一个错误,说“它无法找到该字段的字段 messageConnection ”,因为该字段现在类似于 messageConnection({ after: 'jfds1223asdhfl', first: 50, before: null, last: null }) . Apollo docs说应该在查询中使用 @connection 指令来解决这个问题 . 我试图更新查询,看起来像这样:

thread(id: "asdf") {
  messageConnection(...) @connection(key: "messageConnection") {
    edges {
      cursor
      node { ...messageInfo }
    }
  }
}

不幸的是,当我使用它时,返回并正确显示乐观更新,但是一旦服务器返回存储的实际消息,我就会收到一条错误信息 "Missing field cursor in { node: { id: '...', timestamp: '...'" ,因为很明显服务器返回的消息不是 MessageConnectionEdge ,它是's just the node, and thusly doesn'有一个光标字段 .

我如何告诉Apollo只替换乐观响应的节点,而不是整个边缘?有没有其他方法可以解决原始问题?

2 回答

  • 0

    我会对此有所了解 .

    没有看到突变,我会认为它看起来像下面这样 .

    mutation NewMessage($message: String!, $threadId: ID!) {
      sendMessage(message: $message, threadId: $threadId) {
        ...messageInfo
      }
    }
    

    如果是这种情况,那么推断消息应该在连接中的哪个位置可能是不可靠的 . 由于游标是不透明的字符串,因此我们无法确定此消息是否应该在最新消息之后 .

    相反,我会尝试以下内容 .

    mutation NewMessage(message: String!, threadId: ID!, $after: Cursor, first: Int) {
    
      sendMessage(message: $message, threadId: $threadId) {
        messageConnection(
          after: $after,
          first: $first,
          before: null,
          last: null
        ) @connection(key: "messageConnection") {
          edges {
            cursor
            node { ...messageInfo }
          }
        }
      }
    }
    

    此连接应包括新消息以及之后添加的任何其他消息 .

  • 1

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

    TL;DR: If you have a subscription on the same data as a mutation is changing, make sure to include the same fields in both update methods!

    订阅方法如下所示:

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

    如果你有好眼睛,你会立即发现问题:插入的边缘不提供光标 - 这正是Apollo Client在警告中告诉我们的!修复是将光标添加到插入的边缘:

    { node: newMessage, cursor: newMessage.id, __typename: 'ThreadMessageEdge' }
    

    希望这有助于其他人遇到此警告,请确保三重检查订阅和变异 update 方法!

相关问题