Skip to content
Merged
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
1 change: 1 addition & 0 deletions docs/src/pages/docs/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ title: Examples
- Playground (with devtools) - [CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-query/tree/master/examples/playground) - [Source](./examples/playground)
- Star Wars (with devtools) - [CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-query/tree/master/examples/star-wars) - [Source](./examples/star-wars)
- Rick And Morty (with devtools) - [CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-query/tree/master/examples/rick-morty) - [Source](./examples/rick-morty)
- Nextjs - [CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-query/tree/master/examples/nextjs) - [Source](./examples/nextjs)
23 changes: 23 additions & 0 deletions docs/src/pages/docs/examples/nextjs.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
id: nextjs
title: Nextjs SSR
toc: false
---

- [Open in CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-query/tree/master/examples/nextjs)
- [View Source](https://github.com/tannerlinsley/react-query/tree/master/examples/nextjs)

<iframe
src="https://codesandbox.io/embed/github/tannerlinsley/react-query/tree/master/examples/nextjs?autoresize=1&fontsize=14&theme=dark"
title="tannerlinsley/react-query: nextjs"
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
style={{
width: '100%',
height: '80vh',
border: '0',
borderRadius: 8,
overflow: 'hidden',
position: 'static',
zIndex: 0,
}}
></iframe>
25 changes: 25 additions & 0 deletions examples/nextjs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
10 changes: 10 additions & 0 deletions examples/nextjs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Example

In this simple example, we integrate React-Query seamlessly with Next.js data fetching methods to fetch queries in the server and hydrate them in the browser.

In addition to fetching and mutating data, React-Query analyzes your queries and their results to construct a client-side cache of your data, which is kept up to date as further queries and mutations are run.

To run this example:

- `npm install` or `yarn`
- `npm run dev` or `yarn dev`
33 changes: 33 additions & 0 deletions examples/nextjs/components/Header/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react'
import { useRouter } from 'next/router'
import Link from 'next/link'

export const Header = () => {
const { pathname } = useRouter()

return (
<header>
<Link href="/">
<a className={pathname === '/' ? 'is-active' : ''}>Home</a>
</Link>
<Link href="/client-only">
<a className={pathname === '/client-only' ? 'is-active' : ''}>
Client-Only
</a>
</Link>
<style jsx>{`
header {
margin-bottom: 25px;
}
a {
font-size: 14px;
margin-right: 15px;
text-decoration: none;
}
.is-active {
text-decoration: underline;
}
`}</style>
</header>
)
}
19 changes: 19 additions & 0 deletions examples/nextjs/components/InfoBox/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react'

const InfoBox = ({ children }) => (
<div className="info">
<style jsx>{`
.info {
margin-top: 20px;
margin-bottom: 20px;
padding-top: 20px;
padding-bottom: 20px;
border-top: 1px solid #ececec;
border-bottom: 1px solid #ececec;
}
`}</style>
{children}
</div>
)

export { InfoBox }
49 changes: 49 additions & 0 deletions examples/nextjs/components/Layout/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react'

export const Layout = ({ children }) => {
return (
<main>
{children}
<style jsx global>{`
* {
font-family: Menlo, Monaco, 'Lucida Console', 'Liberation Mono',
'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New',
monospace, serif;
}
body {
margin: 0;
padding: 25px 50px;
}
a {
color: #22bad9;
}
p {
font-size: 14px;
line-height: 24px;
}
article {
margin: 0 auto;
max-width: 650px;
}
button {
align-items: center;
background-color: #22bad9;
border: 0;
color: white;
display: flex;
padding: 5px 7px;
transition: background-color 0.3s;
}
button:active {
background-color: #1b9db7;
}
button:disabled {
background-color: #b5bebf;
}
button:focus {
outline: none;
}
`}</style>
</main>
)
}
69 changes: 69 additions & 0 deletions examples/nextjs/components/PostList/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React, { useState } from 'react'
import { usePosts } from '../../hooks/usePosts'

export const PostList = ({ isClient }) => {
const [postCount, setPostCount] = useState(10)
const { data, isFetching } = usePosts(postCount, isClient)
if (isFetching) return <div>Loading</div>

return (
<section>
<ul>
{data?.map((post, index) => (
<li key={post.id}>
<div>
<span>{index + 1}. </span>
<a href="#">{post.title}</a>
</div>
</li>
))}
</ul>
{postCount <= 90 && (
<button
onClick={() => setPostCount(postCount + 10)}
disabled={isFetching}
>
{isFetching ? 'Loading...' : 'Show More'}
</button>
)}
<style jsx>{`
section {
padding-bottom: 20px;
}
li {
display: block;
margin-bottom: 10px;
}
div {
align-items: center;
display: flex;
}
a {
font-size: 14px;
margin-right: 10px;
text-decoration: none;
padding-bottom: 0;
border: 0;
}
span {
font-size: 14px;
margin-right: 5px;
}
ul {
margin: 0;
padding: 0;
}
button:before {
align-self: center;
border-style: solid;
border-width: 6px 4px 0 4px;
border-color: #ffffff transparent transparent transparent;
content: '';
height: 0;
margin-right: 5px;
width: 0;
}
`}</style>
</section>
)
}
4 changes: 4 additions & 0 deletions examples/nextjs/components/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './Layout'
export * from './Header'
export * from './InfoBox'
export * from './PostList'
1 change: 1 addition & 0 deletions examples/nextjs/hooks/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './usePosts'
16 changes: 16 additions & 0 deletions examples/nextjs/hooks/usePosts/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import ky from 'ky-universal'
import { useQuery } from 'react-query'

const fetchPosts = async (_, limit) => {
const offset = limit ?? 10

const parsed = await ky('https://jsonplaceholder.typicode.com/posts').json()
const result = parsed.filter(x => x.id <= offset)
return result
}

const usePosts = limit => {
return useQuery(['posts', limit], fetchPosts)
}

export { usePosts, fetchPosts }
21 changes: 21 additions & 0 deletions examples/nextjs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "nextjs",
"version": "1.0.0",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"ky": "^0.23.0",
"ky-universal": "^0.8.2",
"next": "latest",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-query": "^2.23.0"
},
"license": "MIT",
"devDependencies": {
"react-query-devtools": "^2.4.7"
}
}
15 changes: 15 additions & 0 deletions examples/nextjs/pages/_app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react'
import { ReactQueryCacheProvider } from 'react-query'
import { ReactQueryDevtools } from 'react-query-devtools'
import { Hydrate } from 'react-query/hydration'

export default function App({ Component, pageProps }) {
return (
<ReactQueryCacheProvider>
<Hydrate state={pageProps.dehydratedState}>
<ReactQueryDevtools initialIsOpen={true} />
<Component {...pageProps} />
</Hydrate>
</ReactQueryCacheProvider>
)
}
14 changes: 14 additions & 0 deletions examples/nextjs/pages/client-only.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react'
import { Layout, Header, InfoBox, PostList } from '../components'

const ClientOnly = () => {
return (
<Layout>
<Header />
<InfoBox>ℹ️ This data is loaded on client and not prefetched</InfoBox>
<PostList />
</Layout>
)
}

export default ClientOnly
28 changes: 28 additions & 0 deletions examples/nextjs/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react'
import { QueryCache } from 'react-query'
import { dehydrate } from 'react-query/hydration'
import { Layout, Header, InfoBox, PostList } from '../components'
import { fetchPosts } from '../hooks'

const Home = () => {
return (
<Layout>
<Header />
<InfoBox>ℹ️ This page shows how to use SSG with React-Query.</InfoBox>
<PostList />
</Layout>
)
}

export async function getStaticProps() {
const queryCache = new QueryCache()
await queryCache.prefetchQuery(['posts', 10], fetchPosts)

return {
props: {
dehydratedState: dehydrate(queryCache),
},
}
}

export default Home
Loading