upstash / jstack

Confidently ship high-performance, low-cost Next.js apps
MIT License
948 stars 57 forks source link

Suspense Queries & Hono #4

Open dalechyn opened 2 months ago

dalechyn commented 2 months ago

I think you can replace this code

https://github.com/upstash/jstack/blob/ee3f48a4f07f172c4d191cf2a1b597e3144da76c/src/app/page.tsx#L13-L24

with an even easier implementation by using ReactQueryStreamedHydration and with useSuspenseQuery. I use such in production and have no issues and don't need to prefetch queries by hands.

// <providers>/ReactQuery.ts
'use client'

import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { ReactQueryStreamedHydration } from '@tanstack/react-query-next-experimental'
import * as React from 'react'

function makeQueryClient() {
  return new QueryClient()
}

let browserQueryClient: QueryClient | undefined

function getQueryClient() {
  if (typeof window === 'undefined') {
    // Server: always make a new query client
    return makeQueryClient()
  }
  // Browser: make a new query client if we don't already have one
  // This is very important so we don't re-make a new client if React
  // supsends during the initial render. This may not be needed if we
  // have a suspense boundary BELOW the creation of the query client
  if (!browserQueryClient) browserQueryClient = makeQueryClient()
  return browserQueryClient
}

export function ReactQueryProvider(props: { children: React.ReactNode }) {
  const queryClient = getQueryClient()
  // NOTE: Avoid useState when initializing the query client if you don't
  //       have a suspense boundary between this and the code that may
  //       suspend because React will throw away the client on the initial
  //       render if it suspends and there is no boundary

  return (
    <QueryClientProvider client={queryClient}>
      <ReactQueryStreamedHydration>
        {props.children}
      </ReactQueryStreamedHydration>
    </QueryClientProvider>
  )
}

but also be aware that if a transformer is used in trpc you'll have to pass it to ReactQueryStreamedHydration too.


On the Hono part. Why is it really needed? I had projects with trpc without Hono and they worked fine.

Also fyi hono has a full-typed fetcher that I use instead of trpc nowadays. It doesn't have a native transport support (like superjson), but it is quite easy to write one yourself.

joschan21 commented 2 months ago

im kinda confused by this issue. There is no trpc here, the built-in hono fetcher is how we achieve type-safety in the first place and the superjson implementation already exists. If we can find a good way to make the streamed hydration possible w/ the superjson integration I dont see why not

dalechyn commented 2 months ago

im kinda confused by this issue. There is no trpc here, the built-in hono fetcher is how we achieve type-safety in the first place and the superjson implementation already exists. If we can find a good way to make the streamed hydration possible w/ the superjson integration I dont see why not

oh lol i haven't checked the code and assumed by the file layout it's trpc. great job!

then focusing on the streamed hydration only. It is possible by passing transformer prop to ReactQueryStreamedHydration.