The SnackBase SDK provides React hooks and context providers for seamless integration with React applications.
Installation
Install the SDK and React peer dependency:
npm install @snackbase/sdk react
yarn add @snackbase/sdk react
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
| Prop | Type | Required | Description |
|---|
baseUrl | string | Yes | API base URL |
apiKey | string | No | API key for server authentication |
defaultAccount | string | No | Default account slug |
timeout | number | No | Request timeout (ms) |
maxRetries | number | No | Max retry attempts |
storageBackend | StorageBackend | No | Token storage backend |
enableLogging | boolean | No | Enable request logging |
logLevel | LogLevel | No | Logging 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