tobias-tengler / relay-rsc-poc

https://relay-rsc-poc.vercel.app
13 stars 0 forks source link

Hydrating client side cache? #1

Open FezVrasta opened 5 months ago

FezVrasta commented 5 months ago

Hi, thanks for the POC, it's really awesome!

I noticed that if I run the same query on a RSC and on the client, the client will hit the graphql server even though the RSC has already fetched the required data.

Do you think it could be possible to have RSC components hydrate the client side Relay cache with the data they fetched so that client components can use it?

tobias-tengler commented 5 months ago

The POC currently doesn't support additional queries without loadStreamableQuery in client components. Could you share a concrete example of your case. Maybe we can look into it.

FezVrasta commented 5 months ago

Thanks for the answer Toabias!

I have these 4 components:

// list.server.tsx

export async function List() {
  const data = await getStreamableQuery<listQuery>(
    graphql`
      query listQuery {
        users {
          edges {
            node {
              id
              ...listItemUserFragment
            }
          }
        }
      }
    `,
    {},
  );

  return (
    <Card size="md" variant="elevated" m="$3">
      <Heading pb="$4">Server Side</Heading>
      {data.users.edges.map((item) => (
        <Suspense key={item.node.id} fallback={<div>🌀 Loading...</div>}>
          <ListItemUser userKey={item.node} />
        </Suspense>
      ))}
    </Card>
  );
}
// list-item.server.tsx
export async function ListItemUser({
  userKey,
}: {
  userKey: listItemUserFragment$key;
}) {
  const data = useFragment(
    graphql`
      fragment listItemUserFragment on User {
        email
        id
        name
      }
    `,
    userKey,
  );

  return (
    <Box py="$2">
      <Text>{data.email}</Text>
    </Box>
  );
}
// list.client.tsx

export function List() {
  const data = useLazyLoadQuery<listClientQuery>(
    graphql`
      query listClientQuery {
        users {
          edges {
            node {
              id
              ...listItemClientUserFragment
            }
          }
        }
      }
    `,
    {},
  );

  return (
    <Card size="md" variant="elevated" m="$3">
      <Heading pb="$4">Client Side</Heading>
      {data.users.edges.map((item) => (
        <Suspense key={item.node.id} fallback={<div>🌀 Loading...</div>}>
          <ListItemUser userKey={item.node} />
        </Suspense>
      ))}
    </Card>
  );
}
// list-item.client.tsx
"use client";

export function ListItemUser({
  userKey,
}: {
  userKey: listItemClientUserFragment$key;
}) {
  const data = useFragment(
    graphql`
      fragment listItemClientUserFragment on User {
        email
        id
        name
      }
    `,
    userKey,
  );

  return (
    <Box py="$2">
      <Text>{data.email}</Text>
    </Box>
  );
}

When I render both, I see client-side GraphQL queries firing from the client side components. But since they are querying the same data that was queried by the server side components I wonder if the cache could be used instead?

tobias-tengler commented 5 months ago

Can you try it with the Streamed Responses around the children in List like we're doing it here: https://github.com/tobias-tengler/relay-rsc-poc/blob/main/packages/example/src/app/page.tsx#L26

FezVrasta commented 5 months ago

Thanks, I don't see any difference adding that component around my list.server.tsx return