Skip to content

Commit

Permalink
docs(next-streaming-react-query): initialization (#650)
Browse files Browse the repository at this point in the history
# Overview

<!--
    A clear and concise description of what this pr is about.
 -->

Initialize examples @suspensive/next-streaming-react-query

## PR Checklist

- [x] I did below actions if need

1. I read the [Contributing
Guide](https://github.com/suspensive/react/blob/main/CONTRIBUTING.md)
2. I added documents and tests.
  • Loading branch information
manudeli authored Jan 26, 2024
1 parent 8bebb2a commit 9547fbd
Show file tree
Hide file tree
Showing 30 changed files with 554 additions and 113 deletions.
5 changes: 0 additions & 5 deletions .codesandbox/ci.json

This file was deleted.

1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ on:
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
NEXT_PUBLIC_STREAMING_HTML_URL: ${{ vars.NEXT_PUBLIC_STREAMING_HTML_URL }}
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
Expand Down
2 changes: 1 addition & 1 deletion docs/suspensive.org/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"start": "next start"
},
"dependencies": {
"next": "^14.0.3",
"next": "^14.1.0",
"nextra": "^2.13.2",
"nextra-theme-docs": "^2.13.2",
"react": "^18.2.0",
Expand Down
9 changes: 9 additions & 0 deletions examples/next-streaming-react-query/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/** @type {import('eslint').Linter.Config} */
module.exports = {
root: true,
extends: ['@suspensive/eslint-config/react-ts', 'plugin:@next/next/recommended'],
parserOptions: {
tsconfigRootDir: __dirname,
project: 'tsconfig.json',
},
}
35 changes: 35 additions & 0 deletions examples/next-streaming-react-query/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# 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*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
8 changes: 8 additions & 0 deletions examples/next-streaming-react-query/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
typedRoutes: true,
},
}

module.exports = nextConfig
30 changes: 30 additions & 0 deletions examples/next-streaming-react-query/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "@suspensive/next-streaming-react-query",
"version": "0.1.0",
"private": true,
"scripts": {
"build": "next build",
"dev": "next dev -p 4100",
"lint": "next lint",
"start": "next start"
},
"dependencies": {
"@suspensive/react": "workspace:*",
"@tanstack/query-core": "^5.17.19",
"@tanstack/react-query": "^5.17.19",
"@tanstack/react-query-devtools": "^5.17.19",
"@tanstack/react-query-next-experimental": "^5.17.19",
"axios": "^1.6.5",
"next": "^14.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"tailwindcss": "^3.4.1"
},
"devDependencies": {
"@next/eslint-plugin-next": "^14.1.0",
"@types/react": "^18.2.48",
"@types/react-dom": "^18.2.18",
"autoprefixer": "^10.4.17",
"postcss": "^8.4.33"
}
}
6 changes: 6 additions & 0 deletions examples/next-streaming-react-query/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
1 change: 1 addition & 0 deletions examples/next-streaming-react-query/public/next.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions examples/next-streaming-react-query/public/vercel.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
'use client'

import { useQueryClient } from '@tanstack/react-query'
import React, { Suspense } from 'react'
import { Text } from './components/Text'
import { Text2 } from './components/Text2'
import { query } from '~/query'
import { SuspenseQuery } from '~/react-query'

export const PageClientComponent = () => {
const queryClient = useQueryClient()

return (
<>
<Suspense fallback={<div>waiting 100....</div>}>
<Text ms={100} />
</Suspense>
<Suspense fallback={<div>waiting 200....</div>}>
<Text ms={200} />
</Suspense>
<Suspense fallback={<div>waiting 300....</div>}>
<Text ms={300} />
</Suspense>
<Suspense fallback={<div>waiting 400....</div>}>
<Text ms={400} />
</Suspense>
<Suspense fallback={<div>waiting 500....</div>}>
<Text ms={500} />
</Suspense>
<Suspense fallback={<div>waiting 600....</div>}>
<Text ms={600} />
</Suspense>
<Suspense fallback={<div>waiting 700....</div>}>
<Text ms={700} />
</Suspense>

<button
onClick={() => {
console.log('resetQueries all')
queryClient.resetQueries()
}}
>
resetQueries all
</button>

<button
onClick={() => {
console.log('invalidateQueries 500')
queryClient.invalidateQueries(query.text(500))
}}
>
invalidate 500
</button>

<button
onClick={() => {
console.log('invalidateQueries 200')
queryClient.invalidateQueries(query.text(200))
}}
>
invalidate 200
</button>

<fieldset>
<legend>
combined <code>Suspense</code>-container
</legend>
<Suspense
fallback={
<>
<div>waiting 800....</div>
<div>waiting 900....</div>
<div>waiting 1000....</div>
</>
}
>
<Text ms={800} />
<Text ms={900} />
<Text ms={1000} />
</Suspense>
</fieldset>

<pre>{`Proposal: <SuspenseQuery /> Component`}</pre>
{/* Need to proposal */}
<ul>
<Suspense fallback="loading...">
<SuspenseQuery {...query.text(1100)}>{({ data }) => <Text2>{data}</Text2>}</SuspenseQuery>
</Suspense>
<Suspense fallback="loading...">
<SuspenseQuery {...query.text(1200)}>{({ data }) => <Text2>{data}</Text2>}</SuspenseQuery>
</Suspense>
<Suspense fallback="loading...">
<SuspenseQuery {...query.text(1300)}>{({ data }) => <Text2>{data}</Text2>}</SuspenseQuery>
</Suspense>
</ul>
</>
)
}
9 changes: 9 additions & 0 deletions examples/next-streaming-react-query/src/app/api/text/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { NextResponse } from 'next/server'

const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))

export async function GET(request: Request) {
const ms = Number(new URL(request.url).searchParams.get('wait'))
await sleep(ms)
return NextResponse.json(`${new Date().toISOString()} success to get text waited after ${ms}ms`)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use client'

import { useSuspenseQuery } from '@tanstack/react-query'
import { query } from '~/query'

export const Text = (props: { ms: number }) => {
const { data: text } = useSuspenseQuery(query.text(props.ms))
return <p>result: {text}</p>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { type ComponentProps, forwardRef } from 'react'

export const Text2 = forwardRef<HTMLParagraphElement, ComponentProps<'p'>>((props, ref) => (
<p ref={ref}>result: {props.children}</p>
))
Text2.displayName = 'Text2'
Binary file not shown.
27 changes: 27 additions & 0 deletions examples/next-streaming-react-query/src/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

:root {
--foreground-rgb: 0, 0, 0;
--background-start-rgb: 214, 219, 220;
--background-end-rgb: 255, 255, 255;
}

@media (prefers-color-scheme: dark) {
:root {
--foreground-rgb: 255, 255, 255;
--background-start-rgb: 0, 0, 0;
--background-end-rgb: 0, 0, 0;
}
}

body {
color: rgb(var(--foreground-rgb));
background: linear-gradient(
to bottom,
transparent,
rgb(var(--background-end-rgb))
)
rgb(var(--background-start-rgb));
}
16 changes: 16 additions & 0 deletions examples/next-streaming-react-query/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { Metadata } from 'next'
import { Providers } from './providers'

export const metadata: Metadata = {
title: 'Next HTML Streaming with Suspense',
}

export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
)
}
23 changes: 23 additions & 0 deletions examples/next-streaming-react-query/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { HydrationBoundary, dehydrate } from '@tanstack/react-query'
import { PageClientComponent } from './PageClientComponent'
import { query } from '~/query'
import { getQueryClient } from '~/react-query'

export default async function MyPage() {
const queryClient = getQueryClient()
await Promise.all([
queryClient.prefetchQuery(query.text(100)),
queryClient.prefetchQuery(query.text(200)),
queryClient.prefetchQuery(query.text(300)),
queryClient.prefetchQuery(query.text(400)),
])

const data = queryClient.getQueryData(query.text(100).queryKey)
console.log(data)

return (
<HydrationBoundary state={dehydrate(queryClient)}>
<PageClientComponent />
</HydrationBoundary>
)
}
26 changes: 26 additions & 0 deletions examples/next-streaming-react-query/src/app/providers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'use client'

import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import { ReactQueryStreamedHydration } from '@tanstack/react-query-next-experimental'
import { type ReactNode, useState } from 'react'

export function Providers(props: { children: ReactNode }) {
const [queryClient] = useState(
() =>
new QueryClient({
defaultOptions: {
queries: {
staleTime: 5 * 1000,
},
},
})
)

return (
<QueryClientProvider client={queryClient}>
<ReactQueryStreamedHydration>{props.children}</ReactQueryStreamedHydration>
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
)
}
21 changes: 21 additions & 0 deletions examples/next-streaming-react-query/src/query/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { queryOptions } from '@tanstack/react-query'

const baseURL = (() => {
if (typeof window !== 'undefined') return ''
if (process.env.NEXT_PUBLIC_STREAMING_HTML_URL) return `https://${process.env.NEXT_PUBLIC_STREAMING_HTML_URL}`
return 'http://localhost:4100'
})()

export const query = {
text: <TMs extends number>(ms: TMs) =>
queryOptions({
queryKey: ['query.text', ms],
queryFn: () =>
fetch(`${baseURL}/api/text?wait=${ms}`, {
cache: 'no-store',
}).then(
(res) =>
res.json() as unknown as `${ReturnType<Date['toISOString']>} success to get text waited after ${TMs}ms`
),
}),
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
'use client'

import {
type QueryKey,
type UseSuspenseQueryOptions,
type UseSuspenseQueryResult,
useSuspenseQuery,
} from '@tanstack/react-query'
import type { ReactNode } from 'react'

export const SuspenseQuery = <
TQueryFnData = unknown,
TError = Error,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
>({
children,
...options
}: UseSuspenseQueryOptions<TQueryFnData, TError, TData, TQueryKey> & {
children: (result: UseSuspenseQueryResult<TData, TError>) => ReactNode
}) => children(useSuspenseQuery(options))
6 changes: 6 additions & 0 deletions examples/next-streaming-react-query/src/react-query/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { QueryClient } from '@tanstack/react-query'
import { cache } from 'react'

export const getQueryClient = cache(() => new QueryClient())

export { SuspenseQuery } from './SuspenseQuery'
Loading

0 comments on commit 9547fbd

Please sign in to comment.