Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(examples): Added graphql-hooks example #250

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ frameworks.
| [Houdini] ([Demo][demo32]) | An Houdini example with SvelteKit. |
| [Swift] | A native Swift (iOS & Mac) example. |
| [Swift with `swift-graphql`] | A native Swift (iOS & Mac) example using [swift-graphql](swift-graphql). |
| [graphql-hooks] | This example demonstrates how to query from GraphCMS with graphql-hooks in Next.js. |

### UI Extensions

Expand Down Expand Up @@ -219,6 +220,7 @@ We've crafted a few example [UI extensions](https://graphcms.com/docs/ui-extensi
[swift-graphql]: https://github.com/maticzav/swift-graphql
[houdini]: with-houdini
[demo32]: https://graphcms-with-houdini.vercel.app
[graphql-hooks]: with-graphql-hooks

<!-- UIX -->

Expand Down
25 changes: 25 additions & 0 deletions with-graphql-hooks/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
.next
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
31 changes: 31 additions & 0 deletions with-graphql-hooks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# GraphCMS ⨯ graphql-hooks

[Join our Slack](https://slack.graphcms.com)

This example demonstrates how to query from GraphCMS with `graphql-hooks` in Next.js.

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/import/project?template=https://github.com/GraphCMS/graphcms-examples/tree/master/with-graphql-hooks) [![Clone project](https://graphcms.com/button)](https://app.graphcms.com/clone/0ff23f7a41ce4da69a366ab299cc24d8)

## How to Use

### Download Manually

```bash
npx degit graphcms/graphcms-examples/with-graphql-hooks with-graphql-hooks
```

Install & Run:

```bash
cd with-graphql-hooks
npm install
npm run dev
# or
cd with-graphql-hooks
yarn
yarn dev
```

### Run on Codesandbox

[![Develop with Codesandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/GraphCMS/graphcms-examples/tree/master/with-graphql-hooks)
5 changes: 5 additions & 0 deletions with-graphql-hooks/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
22 changes: 22 additions & 0 deletions with-graphql-hooks/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "graphcms-graphql-hooks",
"private": true,
"version": "0.0.1",
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"graphql-hooks": "^5.11.3",
"graphql-hooks-memcache": "^2.3.1",
"next": "^12.1.6",
"react": "^18.1.0",
"react-dom": "^18.1.0"
},
"devDependencies": {
"@types/node": "^17.0.31",
"@types/react": "^18.0.9",
"typescript": "^4.6.4"
}
}
91 changes: 91 additions & 0 deletions with-graphql-hooks/src/components/Loader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
export const Loader = () => (
<div style={{ width: "50%", height: "50%" }}>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 100 100"
preserveAspectRatio="xMidYMid"
display="block"
>
<title>Loading...</title>
<g fill="#06092b">
<circle cx="60" cy="50" r="4">
<animate
attributeName="cx"
repeatCount="indefinite"
dur="1s"
values="95;35"
keyTimes="0;1"
begin="-0.67s"
/>
<animate
attributeName="fill-opacity"
repeatCount="indefinite"
dur="1s"
values="0;1;1"
keyTimes="0;0.2;1"
begin="-0.67s"
/>
</circle>
<circle cx="60" cy="50" r="4">
<animate
attributeName="cx"
repeatCount="indefinite"
dur="1s"
values="95;35"
keyTimes="0;1"
begin="-0.33s"
/>
<animate
attributeName="fill-opacity"
repeatCount="indefinite"
dur="1s"
values="0;1;1"
keyTimes="0;0.2;1"
begin="-0.33s"
/>
</circle>
<circle cx="60" cy="50" r="4">
<animate
attributeName="cx"
repeatCount="indefinite"
dur="1s"
values="95;35"
keyTimes="0;1"
begin="0s"
/>
<animate
attributeName="fill-opacity"
repeatCount="indefinite"
dur="1s"
values="0;1;1"
keyTimes="0;0.2;1"
begin="0s"
/>
</circle>
</g>
<g transform="translate(-15)" fill="#f231a5">
<path d="M50 50V20a30 30 0 000 60z" />
<path d="M50 50H20a30 30 0 0060 0z">
<animateTransform
attributeName="transform"
type="rotate"
repeatCount="indefinite"
dur="1s"
values="0 50 50;45 50 50;0 50 50"
keyTimes="0;0.5;1"
/>
</path>
<path d="M50 50H20a30 30 0 0160 0z">
<animateTransform
attributeName="transform"
type="rotate"
repeatCount="indefinite"
dur="1s"
values="0 50 50;-45 50 50;0 50 50"
keyTimes="0;0.5;1"
/>
</path>
</g>
</svg>
</div>
);
45 changes: 45 additions & 0 deletions with-graphql-hooks/src/graphql/queries/products.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { useQuery, UseQueryOptions } from "graphql-hooks";

export type ProductQuery = {
id: string;
name: string;
slug: string;
price: number;
description: string;
};

export type ProductsQuery = {
products: {
id: string;
name: string;
slug: string;
price: number;
description: string;
}[];
};

export const GET_PRODUCTS = `
query GetProducts {
products {
id
name
slug
description
price
}
}`;

export const GET_PRODUCT = `
query GetProduct($slug: String!) {
product(where: { slug: $slug }) {
id
name
slug
description
price
}
}`;

export function useQueryProducts(options?: UseQueryOptions) {
return useQuery(GET_PRODUCTS, options);
}
19 changes: 19 additions & 0 deletions with-graphql-hooks/src/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { AppProps } from "next/app";

import { GraphQLClient, ClientContext } from "graphql-hooks";

import "../styles/index.css";

export const client = new GraphQLClient({
url: "https://api-eu-central-1.graphcms.com/v2/ck8sn5tnf01gc01z89dbc7s0o/master",
});

const MyApp = ({ Component, pageProps }: AppProps) => {
return (
<ClientContext.Provider value={client}>
<Component {...pageProps} />;
</ClientContext.Provider>
);
};

export default MyApp;
31 changes: 31 additions & 0 deletions with-graphql-hooks/src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Loader } from "components/Loader";
import { ProductQuery, useQueryProducts } from "graphql/queries/products";
import Link from "next/link";

const Home = (): JSX.Element => {
const { data, loading } = useQueryProducts();

return (
<div className="container">
<h1>All Products</h1>

{loading ? (
<Loader />
) : (
<ul>
{data.products.map((product: ProductQuery) => (
<li key={product.id}>
<Link href={`/product/${product.slug}`}>
<a>{product.name}</a>
</Link>
</li>
))}
</ul>
)}

<p>This example is using graphql-hooks, typescript and next.js</p>
</div>
);
};

export default Home;
85 changes: 85 additions & 0 deletions with-graphql-hooks/src/pages/product/[slug].tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import type { GetStaticProps } from "next";
import { useRouter } from "next/router";
import Link from "next/link";

import { client } from "pages/_app";
import {
GET_PRODUCT,
GET_PRODUCTS,
ProductQuery,
ProductsQuery,
} from "graphql/queries/products";

import { Loader } from "components/Loader";

interface ProductProps {
product: ProductQuery;
}

export default function Product(props: ProductQuery) {
const router = useRouter();

if (router.isFallback) return <Loader />;

return (
<div className="container">
<h1>Product</h1>

<p>
This is the product page: <strong>{props.name}</strong>
</p>

<Link href="/">
<a>Go back to the homepage</a>
</Link>

<div className="product">
<span>
<strong>ID:</strong> {props.id}
</span>

<span>
<strong>Name:</strong> {props.name}
</span>

<span>
<strong>Slug:</strong> {props.slug}
</span>

<span>
<strong>Description:</strong> {props.description}
</span>

<span>
<strong>Price:</strong> ${props.price}
</span>
</div>
</div>
);
}

export async function getStaticPaths() {
const { data } = await client?.request<ProductsQuery>({
query: GET_PRODUCTS,
});

const paths = data?.products?.map(({ slug }) => ({
params: { slug },
}));

return { paths, fallback: true };
}

export const getStaticProps: GetStaticProps = async ({ params }) => {
const { data } = await client?.request<ProductProps>({
query: GET_PRODUCT,
variables: {
slug: params.slug,
},
});

return {
revalidate: 60,
props: data.product,
};
};
Loading