Get All Connections for a Key with React Relay?

Posted on Sat Jun 01 2024

React Relay is a popular library to connect the GraphQL backend with React.js-based front-end applications. If you are already using it, you know how it provides two different ways to modify the relay store. One is using directives like @prependEdge. Another method is to programmatically modify the relay store. When your application is in the early stages, you can just get everything done with the directives. But once it grows, you often have to manually modify the react store more often than you like to.

Problem

When you are modifying the store programmatically, there are many helpful helper methods available. One such key helper method is called ConnectionHandler.getConnection. It gets you the connection you want to modify by passing a parent record and key. Suppose you have a simple connection for displaying members for a user, denoted by the key Members_user_members. It is fairly simple to access this connection.

1const user = store.get(userID);
2const connection = ConnectionHandler.getConnection(user, 'Members_user_members');
3

But what if you want to add pagination and search to this connection? That means three variables :- $first, $after, $query for filters. getConnection will only return connection that match exact filters passed to it. There is an article about this on the Relay website.

So if you want to remove an edge from this connection, you will have to :-

  • Keep track of all possible values for filters
  • Get a connection for each such combination
  • Remove the edge from that combination

There is a relevant issue about this. This issue requests a new helper method called getConnections.

Solution

Such a connection will store data roughly in this format.

relay-store-data

Below is the implementation of the helper method, which will get all connections for a key. It generates a bare connection identity and extracts records based on that identity, regardless of different filter arguments.

1import { ConnectionHandler, RecordProxy } from 'relay-runtime';
2import type { ReadOnlyRecordProxy } from 'relay-runtime/lib/store/RelayStoreTypes';
3
4function connectionExists(
5  connection: RecordProxy | null | undefined,
6): connection is RecordProxy {
7  return !!connection;
8}
9
10export function getConnections(
11  record: ReadOnlyRecordProxy,
12  key: string,
13): Array<RecordProxy> {
14  const dataID = record.getDataID();
15  const bareConnectionId = ConnectionHandler.getConnectionID(dataID, key);
16
17  // @ts-ignore
18  const handleKeys = record._mutator._base.getRecordIDs().filter(
19    // ignore edges:0, pageInfo suffix
20    (id: string) => id.startsWith(bareConnectionId) && id.endsWith(')'),
21  );
22
23  return (
24    (handleKeys as string[])
25      // @ts-ignore
26      .map((handleKey) => record._source.get(handleKey))
27      .filter(connectionExists)
28  );
29}

After getting access to all the connections for a given key, you may modify them as per your application logic.