なぽろぐ

気ままに感じたことを記事にまとめます。

@apollo/client を suspense 対応させたライブラリを作った

@apollo/client でも suspense したい!

React18 がでたし、loading, data という関係ともおさらばしたい。でも @apollo/client は suspense に対応してない.....

ちょっと困ったので作りました。

github.com

以前作成したライブラリと @apollo/client を併用しています。

ApolloClient.watchQuery からデータを取得しているので refetchQueriesuseQuery(gql).refetch() とも連携できてるはずです。

suspense された useQuery を体験する

github.com

前準備

yarn add @naporin0624/react-flowder rxjs
yarn add graphql @apollo/client

query は長いので畳んでおきます。

import { gql, TypedDocumentNode } from "@apollo/client";

const USER_FIELDS = gql`
  fragment CoreUserFields on User {
    login
    name
    websiteUrl
    avatarUrl
  }
`;

const sampleQuery: SampleQuery = gql`
  ${USER_FIELDS}
  query SampleQuery {
    search(query: "repo:apollographql/apollo is:issue", type: ISSUE, first: 5) {
      issueCount
      nodes {
        ... on Issue {
          id
          number
          title
          createdAt
        }
      }
    }

    user(login: "naporin0624") {
      ...CoreUserFields
    }
  }
`;

App.tsx

import React, { useMemo } from "react";
import {
  useSyncQuery,
  useApolloReset,
} from "@naporin0624/react-flowder/apollo";


const App = () => {
  const data = useSyncQuery(
    sampleQuery,
    useMemo(() => ({ pollInterval: 10000, variables: {} }), [])
  );
  const reset = useApolloReset();

  return (
    <div>
      <button onClick={reset}>reset</button>
      <p style={{ whiteSpace: "pre-wrap" }}>{JSON.stringify(data, null, 2)}</p>
    </div>
  );
};

export default memo(App)

index.tsx

import React, { Suspense } from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
import { Provider as DatasourceProvider } from "@naporin0624/react-flowder";
import { ApolloClient, InMemoryCache, ApolloProvider } from "@apollo/client";

const token = import.meta.env.VITE_GITHUB_TOKEN;
const client = new ApolloClient({
  uri: "https://api.github.com/graphql",
  headers: { authorization: `Bearer ${token}` },
  cache: new InMemoryCache(),
});

createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <ApolloProvider client={client}>
      <DatasourceProvider>
        <Suspense fallback={null}>
          <App />
        </Suspense>
      </DatasourceProvider>
    </ApolloProvider>
  </React.StrictMode>
);