Saltar al contenido principal

Server-side rendering

How @feelrift/react stays compatible with Next.js App Router (React Server Components), Astro islands, and Vite SPAs without framework-specific packages — and what consumers need to do to hold the SDK's guarantees.

What the SDK guarantees

These invariants are tested on every release. You can rely on them in production.

1. "use client"; directives survive the build

Every hook and component module ships with "use client"; at the top so Next.js App Router treats it as a client component. The directive is preserved through the build pipeline; importing an SDK hook or component into a server component fails at build time with a clear error rather than at runtime with a hydration warning.

2. The /client entry is React-free

Non-React consumers (Vue, Svelte, server-side Node, edge runtimes) can import the typed API client and RiftApiError without pulling React into their bundle:

import { createRiftClient, RiftApiError } from "@feelrift/react/client";

const client = createRiftClient({ baseUrl: "https://api.feelrift.com" });
const config = await client.getConfig("evt_summerfest_2026");

3. The /client entry loads in Node without DOM globals

The /client entry has no load-time dependency on window, document, or any other browser-only global. Safe to import from server-side Node, edge runtimes, and worker contexts.

4. Heavy peers are externalized

React, ReactDOM, the JSX runtime, and the Stripe peers are externalized — the SDK doesn't bundle them, your tree provides them.

What the SDK does at runtime to stay hydration-safe

useHasHydrated() gate

The SDK defers reading any persisted state (reservation token, order id) until after mount, so the first server render matches the first client render — no React 19 hydration warnings. SDK components already respect this; custom components that read persisted state directly should gate on useHasHydrated() the same way:

import { useHasHydrated, useRiftStore } from "@feelrift/react";

function MyReservationBadge() {
const hasHydrated = useHasHydrated();
const reservation = useRiftStore((s) => s.reservation);
if (!hasHydrated) return null;
return reservation ? <span>{reservation.data.id}</span> : null;
}

clientSecret is never persisted

The Stripe PaymentIntent clientSecret is deliberately left out of the persistence allow-list. PaymentIntents can be canceled server-side between sessions; rehydrating a stale secret produces raw Stripe errors. On resume, <CheckoutForm> re-calls the checkout endpoint with the persisted reservation token to mint a fresh PaymentIntent.

Stripe.js loads lazily

<RiftEvent> only imports the Stripe runtime when the event is paid (ticketingConfig.stripe !== null). Disabled Ticketing and free-event embeds never trigger the import, so the optional peer stays opt-in and Stripe's payload never lands in your initial bundle.

Consumer checklist by framework

Next.js App Router

  • Import + use the SDK from any client component (file with "use client";). Importing into a server component fails at build time with a clear "client-only module" error.
  • Mount the provider chain (<RiftProvider> + <RiftEvent>) inside a client component that wraps the affected layout segment. See Installation → Next.js App Router.
  • For server-side data fetching (RSC, route handlers, server actions), import from @feelrift/react/client rather than the root. Build a typed client with createRiftClient(...) and call methods such as client.getConfig(...), client.getTicketingConfig(...), and client.getAvailability(...).

Next.js Pages Router

  • Mount the provider chain in _app.tsx. The SDK works inside both page components and any children of <Component />.
  • Use getServerSideProps / getStaticProps with the @feelrift/react/client entry for server-side data — same pattern as App Router.

Astro

  • Wrap SDK components in a client:idle or client:visible island. The "use client"; directives are benign string literals in Astro's React integration; the islands are what actually defer hydration.
  • Server-side rendering inside an Astro page (no client directive) works for read-only flows that use only the typed client methods, not the hooks.

Vite SPA

  • No special setup. The directives are no-ops; the SDK works like any React library.
  • Code-split heavy SDK components (<CheckoutForm> in particular — it pulls Stripe Elements) with React.lazy if the embed isn't visible on first paint.

Troubleshooting hydration warnings

If you hit a hydration warning specific to one of the target frameworks:

  1. Check that you're importing from @feelrift/react, not deep into @feelrift/react/dist/*.
  2. Confirm your bundler hasn't stripped the "use client" directives (most React 19+ tooling preserves them automatically; older toolchains may need a plugin).
  3. File an issue with the framework version, the failing component, and the warning text.
  • Installation — framework-specific provider placement.
  • RiftProvider — the provider that triggers the post-mount rehydration.