Skip to content

Commit 8f707d4

Browse files
Add Convex example (vercel#38129)
Adds an example using [Convex](https://convex.dev/). ## Documentation / Examples - [x] Make sure the linting passes by running `pnpm lint` - [x] The examples guidelines are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing.md#adding-examples) Co-authored-by: Balázs Orbán <[email protected]>
1 parent 5e2ad29 commit 8f707d4

File tree

14 files changed

+412
-0
lines changed

14 files changed

+412
-0
lines changed

examples/convex/.gitignore

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# next.js
12+
/.next/
13+
/out/
14+
15+
# production
16+
/build
17+
18+
# misc
19+
.DS_Store
20+
*.pem
21+
22+
# debug
23+
npm-debug.log*
24+
yarn-debug.log*
25+
yarn-error.log*
26+
27+
# local env files
28+
.env.local
29+
.env.development.local
30+
.env.test.local
31+
.env.production.local
32+
33+
# vercel
34+
.vercel
35+
36+
# convex
37+
convex/_generated
38+
39+
# typescript
40+
*.tsbuildinfo

examples/convex/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Convex
2+
3+
This example demonstrates the Convex global state management framework.
4+
5+
## Deploy your own
6+
7+
Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example):
8+
9+
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/convex&project-name=convex&repository-name=convex)
10+
11+
## How to use
12+
13+
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example:
14+
15+
```bash
16+
npx create-next-app --example with-convex with-convex-app
17+
# or
18+
yarn create next-app --example with-convex with-convex-app
19+
# or
20+
pnpm create next-app --example with-convex with-convex-app
21+
```
22+
23+
After creating a [Convex account](https://www.convex.dev) and getting a beta key,
24+
25+
```bash
26+
npx convex init --beta-key <your beta key>
27+
```
28+
29+
Next, push the Convex functions for this project.
30+
31+
```bash
32+
npx convex push
33+
```
34+
35+
Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).

examples/convex/convex/README.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Welcome to your functions directory
2+
3+
Write your convex functions in this directory.
4+
5+
A query function (how you read data) looks like this:
6+
7+
```typescript
8+
// getCounter.ts
9+
import { query } from './_generated/server'
10+
11+
export default query(async ({ db }): Promise<number> => {
12+
const counterDoc = await db.table('counter_table').first()
13+
console.log('Got stuff')
14+
if (counterDoc === null) {
15+
return 0
16+
}
17+
return counterDoc.counter
18+
})
19+
```
20+
21+
A mutation function (how you write data) looks like this:
22+
23+
```typescript
24+
// incrementCounter.ts
25+
import { mutation } from './_generated/server'
26+
27+
export default mutation(async ({ db }, increment: number) => {
28+
let counterDoc = await db.table('counter_table').first()
29+
if (counterDoc === null) {
30+
counterDoc = {
31+
counter: increment,
32+
}
33+
db.insert('counter_table', counterDoc)
34+
} else {
35+
counterDoc.counter += increment
36+
db.replace(counterDoc._id, counterDoc)
37+
}
38+
// Like console.log but relays log messages from the server to client.
39+
console.log(`Value of counter is now ${counterDoc.counter}`)
40+
})
41+
```
42+
43+
The convex cli is your friend. See everything it can do by running
44+
`npx convex -h` in your project root directory. To learn more, launch the docs
45+
with `npx convex docs`.

examples/convex/convex/getCounter.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { query } from './_generated/server'
2+
3+
export default query(async ({ db }, counterName: string): Promise<number> => {
4+
const counterDoc = await db
5+
.table('counter_table')
6+
.filter((q) => q.eq(q.field('name'), counterName))
7+
.first()
8+
console.log('Got stuff')
9+
if (counterDoc === null) {
10+
return 0
11+
}
12+
return counterDoc.counter
13+
})
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { mutation } from './_generated/server'
2+
3+
export default mutation(
4+
async ({ db }, counterName: string, increment: number) => {
5+
let counterDoc = await db
6+
.table('counter_table')
7+
.filter((q) => q.eq(q.field('name'), counterName))
8+
.first()
9+
if (counterDoc === null) {
10+
counterDoc = {
11+
name: counterName,
12+
counter: increment,
13+
}
14+
db.insert('counter_table', counterDoc)
15+
} else {
16+
counterDoc.counter += increment
17+
db.replace(counterDoc._id, counterDoc)
18+
}
19+
// Like console.log but relays log messages from the server to client.
20+
console.log(`Value of counter is now ${counterDoc.counter}`)
21+
}
22+
)

examples/convex/next-env.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/// <reference types="next" />
2+
/// <reference types="next/image-types/global" />
3+
4+
// NOTE: This file should not be edited
5+
// see https://nextjs.org/docs/basic-features/typescript for more information.

examples/convex/package.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"private": true,
3+
"scripts": {
4+
"dev": "next dev",
5+
"build": "next build",
6+
"start": "next start"
7+
},
8+
"dependencies": {
9+
"next": "latest",
10+
"react": "^18.2.0",
11+
"react-dom": "^18.2.0",
12+
"convex-dev": "0.1.4"
13+
},
14+
"devDependencies": {
15+
"@types/node": "~16.11.12",
16+
"@types/react": "17.0.45",
17+
"@types/react-dom": "17.0.17",
18+
"typescript": "^4.7.3"
19+
}
20+
}

examples/convex/pages/_app.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import '../styles/globals.css'
2+
import type { AppProps } from 'next/app'
3+
4+
import { ConvexProvider, ConvexReactClient } from 'convex-dev/react'
5+
import convexConfig from '../convex.json'
6+
const convex = new ConvexReactClient(convexConfig.origin)
7+
8+
function MyApp({ Component, pageProps }: AppProps) {
9+
return (
10+
<ConvexProvider client={convex}>
11+
<Component {...pageProps} />;
12+
</ConvexProvider>
13+
)
14+
}
15+
16+
export default MyApp

examples/convex/pages/index.tsx

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import type { NextPage } from 'next'
2+
import Head from 'next/head'
3+
import Image from 'next/image'
4+
import styles from '../styles/Home.module.css'
5+
import { useQuery, useMutation } from '../convex/_generated/react'
6+
import { useCallback } from 'react'
7+
8+
const Home: NextPage = () => {
9+
const counter = useQuery('getCounter', 'clicks') ?? 0
10+
const increment = useMutation('incrementCounter')
11+
const incrementByOne = useCallback(() => increment('clicks', 1), [increment])
12+
13+
return (
14+
<div className={styles.container}>
15+
<Head>
16+
<title>Next.js with Convex</title>
17+
<meta name="description" content="Generated by create next app" />
18+
<link rel="icon" href="/favicon.ico" />
19+
</Head>
20+
21+
<main className={styles.main}>
22+
<h1 className={styles.title}>
23+
Welcome to <a href="https://nextjs.org">Next.js</a> with{' '}
24+
<a href="https://convex.dev">Convex</a>
25+
</h1>
26+
27+
<p className={styles.description}>
28+
{"Here's the counter:"} {counter}
29+
</p>
30+
<button className={styles.button} onClick={incrementByOne}>
31+
Add One!
32+
</button>
33+
</main>
34+
35+
<footer className={styles.footer}>
36+
<a
37+
href="https://www.convex.dev/"
38+
target="_blank"
39+
rel="noopener noreferrer"
40+
>
41+
Powered by{' '}
42+
<span className={styles.logo}>
43+
<Image src="/convex.svg" alt="Convex Logo" width={90} height={18} />
44+
</span>
45+
</a>
46+
</footer>
47+
</div>
48+
)
49+
}
50+
51+
export default Home

examples/convex/public/convex.svg

Lines changed: 19 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)