This article's content
Generate client side GraphQL hooks for URQL

Assume you have your GraphQL server running on localhost:3333, you have your React app setup and you are now at the point at which you want to request and manipulate data from your GraphQL server via URQL.

You set up your React app to use URQL client with devtools enabled and adding a potential token from your localStorage to every request:

main.tsx
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import { devtoolsExchange } from "@urql/devtools";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import { createClient, defaultExchanges, Provider } from "urql";
import App from "./app/app";
const client = createClient({
url: "http://localhost:3333/graphql",
exchanges: [devtoolsExchange, ...defaultExchanges],
fetchOptions: () => {
const token = localStorage.getItem("token");
return {
headers: { authorization: token ? `Bearer ${token}` : "" },
};
},
});
const root = createRoot(document.getElementById("root") as HTMLElement);
root.render(
<StrictMode>
<Provider value={client}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
</StrictMode>,
);
import { devtoolsExchange } from "@urql/devtools"; import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import { BrowserRouter } from "react-router-dom"; import { createClient, defaultExchanges, Provider } from "urql"; import App from "./app/app"; const client = createClient({ url: "http://localhost:3333/graphql", exchanges: [devtoolsExchange, ...defaultExchanges], fetchOptions: () => { const token = localStorage.getItem("token"); return { headers: { authorization: token ? `Bearer ${token}` : "" }, }; }, }); const root = createRoot(document.getElementById("root") as HTMLElement); root.render( <StrictMode> <Provider value={client}> <BrowserRouter> <App /> </BrowserRouter> </Provider> </StrictMode>, );
import { devtoolsExchange } from "@urql/devtools";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import { createClient, defaultExchanges, Provider } from "urql";

import App from "./app/app";

const client = createClient({
  url: "http://localhost:3333/graphql",
  exchanges: [devtoolsExchange, ...defaultExchanges],
  fetchOptions: () => {
    const token = localStorage.getItem("token");
    return {
      headers: { authorization: token ? `Bearer ${token}` : "" },
    };
  },
});

const root = createRoot(document.getElementById("root") as HTMLElement);
root.render(
  <StrictMode>
    <Provider value={client}>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </Provider>
  </StrictMode>,
);

Next you add a Container component which executes your request:

NotificationsTestPageContainer.tsx
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import { FC, HTMLAttributes } from "react";
const TestNotificationQuery = `
query {
testNotifications {
content
subject
_id
}
}
`;
export const NotificationsTestPageContainer: FC<Props> = () => {
const [result] = useQuery({
query: TestNotificationQuery
});
const { data, fetching, error } = result;
if (fetching) return <p>Loading...</p>;
if (error) return <p>Oh no... {error.message}</p>;
return (
<NotificationsTestPage testNotifications={data.testNotifications} />
);
};
import { FC, HTMLAttributes } from "react"; const TestNotificationQuery = ` query { testNotifications { content subject _id } } `; export const NotificationsTestPageContainer: FC<Props> = () => { const [result] = useQuery({ query: TestNotificationQuery }); const { data, fetching, error } = result; if (fetching) return <p>Loading...</p>; if (error) return <p>Oh no... {error.message}</p>; return ( <NotificationsTestPage testNotifications={data.testNotifications} /> ); };
import { FC, HTMLAttributes } from "react";

const TestNotificationQuery = `
  query {
    testNotifications {
      content
      subject
      _id
    }
  }
`;

export const NotificationsTestPageContainer: FC<Props> = () => {
  const [result] = useQuery({
    query: TestNotificationQuery
  });

  const { data, fetching, error } = result;

  if (fetching) return <p>Loading...</p>;
  if (error) return <p>Oh no... {error.message}</p>;

  return (
    <NotificationsTestPage testNotifications={data.testNotifications} />
  );
};

That’s the manual way to do it, but be could do a little better: We want to extract our GQL and also want to generate the hook. We start by installing and setting up the code generator from the-guild.dev:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
yarn add graphql
yarn add -D typescript
yarn add -D @graphql-codegen/cli
yarn add -D @graphql-codegen/client-preset
yarn add -D @graphql-codegen/typescript-urql
yarn add graphql yarn add -D typescript yarn add -D @graphql-codegen/cli yarn add -D @graphql-codegen/client-preset yarn add -D @graphql-codegen/typescript-urql
yarn add graphql
yarn add -D typescript
yarn add -D @graphql-codegen/cli
yarn add -D @graphql-codegen/client-preset
yarn add -D @graphql-codegen/typescript-urql

and create:

codegen.yml
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
overwrite: true
schema: "http://localhost:3333/graphql"
documents: "./libs/whatever/src/lib/**/*.graphql"
generates:
libs/types/src/generated/graphql.tsx:
plugins:
- "typescript"
- "typescript-operations"
- "typescript-urql"
config:
withHooks: true
overwrite: true schema: "http://localhost:3333/graphql" documents: "./libs/whatever/src/lib/**/*.graphql" generates: libs/types/src/generated/graphql.tsx: plugins: - "typescript" - "typescript-operations" - "typescript-urql" config: withHooks: true
overwrite: true
schema: "http://localhost:3333/graphql"
documents: "./libs/whatever/src/lib/**/*.graphql"
generates:
  libs/types/src/generated/graphql.tsx:
    plugins:
      - "typescript"
      - "typescript-operations"
      - "typescript-urql"
    config:
      withHooks: true

Extract the GQL to its own file

notifications.graphql
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
query getTestNotifications {
testNotifications {
content
subject
_id
}
}
query getTestNotifications { testNotifications { content subject _id } }
query getTestNotifications {
  testNotifications {
    content
    subject
    _id
  }
}

To generate the code to ./libs/whatever/src/lib/*/.graphql you execute this:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
graphql-codegen --config codegen.yml
graphql-codegen --config codegen.yml
graphql-codegen --config codegen.yml

Now you can use the generated hook instead of the old one:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// const [result] = useQuery({
// query: TestNotificationQuery
// });
const [result] = useGetTestNotificationsQuery();
// const [result] = useQuery({ // query: TestNotificationQuery // }); const [result] = useGetTestNotificationsQuery();
// const [result] = useQuery({
//   query: TestNotificationQuery
// });

const [result] = useGetTestNotificationsQuery();

About Author

Mathias Bothe To my job profile

I am Mathias from Heidelberg, Germany. I am a passionate IT freelancer with 15+ years experience in programming, especially in developing web based applications for companies that range from small startups to the big players out there. I create Bosycom and initiated several software projects.