Grigory Glushko
Grigory Glushko

Reputation: 11

What is the proper way to implement chat "history" like pagination with relay connections?

I am trying to make an example chat with relay and subscriptions. I've managed to make it work in some fashion. The problem is that older messages are pushed from the view when new message is added by either mutation or subscription. But it is not an actual behavior we expect from chat. We want to all loaded messages from history stay in list when new message is added to the bottom.

playground example(without subscription, but mutation is enough)

with subscriptions

So there we have:

We can increment $last from container but there is no way I know of to increment it on addition of new connection node in store.

Some workarounds we've thought of with my colleague:

  1. Increment last in AddMsg mutation callback. It will work for mutation, but not for subscription. And the oldest message will be pushed out still by optimistic response, then added back again after response.
  2. Try to increment $last in componentWillReceiveProps. This seems very hacky solution, because:

    • there is no way to safely decide what to do with $last, knowing previous and next props only.
    • componentWillReceiveProps will be called several times for mutation (optimistic response, than $last change, than actual response)
  3. Do not use $last variable. Instead fetch msgs(last: 100000000) and make server return default count on first response (2 in out example) if last is big enough. In this case all will work as expected. But backend will actually fail to comply to relay-graphql connection spec.

  4. Split MsgsContainer viewer fragment to 2 (or more) fragments:

    • history "... msgs(last: $last, before: $lastMsgCursor) { ..."
    • newMessages "... msgs(after: $lastMsgCursor) { ..."

    The problem here is message with $lastMsgCursor will be excluded from both history and newMessages fragments, so may be we need third fragment: lastMessage. But then, how to query it?

None of this ideas seem to be a good way to go. So I wonder, what will be proper way to make history like pagination work?

Upvotes: 1

Views: 713

Answers (1)

steveluscher
steveluscher

Reputation: 4228

A common pattern is to ‘make room’ for the new item, perform the mutation, and rollback the room in case the mutation fails:

addMsg() {
  // Make room for the new item.
  this.props.relay.setVariables({ 
    last: this.props.relay.variables.last + 1,
  });
  // Perform the mutation.
  this.props.relay.commitUpdate(
    new AddMsgMutation({ 
      text: "new msg", 
      viewer: this.props.viewer,
    }),
    {
      onFailure: () => {
        // Roll back the room if the mutation fails.
        this.props.relay.setVariables({ 
          last: this.props.relay.variables.last - 1,
        });
      },
    },
  );
}

Updated Playground: (link)

Upvotes: 0

Related Questions