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.