Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.snackbase.dev/llms.txt

Use this file to discover all available pages before exploring further.

The SnackBase SDK provides React hooks and context providers for seamless integration with React applications.

Installation

Install the SDK and React peer dependency:
npm
npm install @snackbase/sdk react
yarn
yarn add @snackbase/sdk react
pnpm
pnpm add @snackbase/sdk react
React 18 or higher is required for the React integration.

Setup

1. Wrap with Provider

Wrap your application with SnackBaseProvider:
import { SnackBaseProvider } from "@snackbase/sdk/react";

function App() {
  return (
    <SnackBaseProvider
      baseUrl="https://api.example.com"
      apiKey={process.env.SNACKBASE_API_KEY}
      defaultAccount="my-account"
    >
      <YourApp />
    </SnackBaseProvider>
  );
}

2. Use Hooks

Use the provided hooks in your components:
import { useAuth, useRecord } from "@snackbase/sdk/react";

function Profile() {
  const { user, login, logout } = useAuth();
  const { data: profile, loading } = useRecord("profiles", user?.id);

  if (!user) {
    return <button onClick={() => login(email, password)}>Login</button>;
  }

  return (
    <div>
      <h1>Welcome, {user.email}</h1>
      {loading ? <p>Loading...</p> : <pre>{JSON.stringify(profile, null, 2)}</pre>}
      <button onClick={logout}>Logout</button>
    </div>
  );
}

Provider Props

PropTypeRequiredDescription
baseUrlstringYesAPI base URL
apiKeystringNoAPI key for server authentication
defaultAccountstringNoDefault account slug
timeoutnumberNoRequest timeout (ms)
maxRetriesnumberNoMax retry attempts
storageBackendStorageBackendNoToken storage backend
enableLoggingbooleanNoEnable request logging
logLevelLogLevelNoLogging level

Environment-Specific Setup

Development

<SnackBaseProvider
  baseUrl={process.env.NEXT_PUBLIC_SNACKBASE_URL!}
  defaultAccount="dev-account"
  enableLogging={true}
  logLevel="debug"
>
  <App />
</SnackBaseProvider>

Production

<SnackBaseProvider
  baseUrl={process.env.NEXT_PUBLIC_SNACKBASE_URL!}
  apiKey={process.env.SNACKBASE_API_KEY}
  enableLogging={false}
>
  <App />
</SnackBaseProvider>

With Next.js

App Router

// app/layout.tsx
import { SnackBaseProvider } from "@snackbase/sdk/react";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <SnackBaseProvider
          baseUrl={process.env.NEXT_PUBLIC_SNACKBASE_URL!}
        >
          {children}
        </SnackBaseProvider>
      </body>
    </html>
  );
}

Pages Router

// pages/_app.tsx
import type { AppProps } from "next/app";
import { SnackBaseProvider } from "@snackbase/sdk/react";

export default function App({ Component, pageProps }: AppProps) {
  return (
    <SnackBaseProvider
      baseUrl={process.env.NEXT_PUBLIC_SNACKBASE_URL!}
    >
      <Component {...pageProps} />
    </SnackBaseProvider>
  );
}

With Vite

// src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { SnackBaseProvider } from "@snackbase/sdk/react";
import App from "./App";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <SnackBaseProvider
      baseUrl={import.meta.env.VITE_SNACKBASE_URL}
    >
      <App />
    </SnackBaseProvider>
  </React.StrictMode>
);

Access Client Directly

For advanced use cases, access the client directly:
import { useSnackBase } from "@snackbase/sdk/react";

function AdvancedComponent() {
  const client = useSnackBase();

  useEffect(() => {
    // Use client directly
    client.collections.list().then((collections) => {
      console.log("Collections:", collections);
    });
  }, [client]);

  return <div>Check console for collections</div>;
}

Server-Side Rendering

For SSR, skip provider on server:
import { SnackBaseProvider } from "@snackbase/sdk/react";

function App({ children }: { children: React.ReactNode }) {
  // Only provide on client
  if (typeof window === "undefined") {
    return <>{children}</>;
  }

  return (
    <SnackBaseProvider
      baseUrl={process.env.NEXT_PUBLIC_SNACKBASE_URL!}
    >
      {children}
    </SnackBaseProvider>
  );
}

TypeScript Support

The React integration is fully typed:
import { useAuth, useRecord } from "@snackbase/sdk/react";
import type { User, Post } from "@snackbase/sdk";

function Profile() {
  const { user } = useAuth<User>();
  const { data: post } = useRecord<Post>("posts", "post-id");

  // user and post are fully typed
  console.log(user?.email);
  console.log(post?.title);
}

Complete Example

import { SnackBaseProvider, useAuth, useRecord } from "@snackbase/sdk/react";

function App() {
  return (
    <SnackBaseProvider
      baseUrl="https://api.example.com"
      defaultAccount="my-account"
    >
      <Main />
    </SnackBaseProvider>
  );
}

function Main() {
  const { user, login, logout, isLoading } = useAuth();

  if (isLoading) {
    return <div>Loading...</div>;
  }

  if (!user) {
    return <LoginForm onLogin={login} />;
  }

  return (
    <div>
      <header>
        <h1>Welcome, {user.email}</h1>
        <button onClick={logout}>Logout</button>
      </header>
      <Dashboard />
    </div>
  );
}

function LoginForm({ onLogin }: { onLogin: (credentials: any) => Promise<void> }) {
  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    const form = e.currentTarget;
    const email = (form.elements.namedItem("email") as HTMLInputElement).value;
    const password = (form.elements.namedItem("password") as HTMLInputElement).value;
    await onLogin({ email, password });
  };

  return (
    <form onSubmit={handleSubmit}>
      <input name="email" type="email" placeholder="Email" required />
      <input name="password" type="password" placeholder="Password" required />
      <button type="submit">Login</button>
    </form>
  );
}

function Dashboard() {
  const { user } = useAuth();
  const { data: profile, loading, error } = useRecord("profiles", user?.id || "");

  if (loading) return <div>Loading profile...</div>;
  if (error) return <div>Error loading profile</div>;

  return (
    <div>
      <h2>Profile</h2>
      <pre>{JSON.stringify(profile, null, 2)}</pre>
    </div>
  );
}

Next Steps