@pubflow/react ​
React integration for Flowfull Clients with hooks, components, and SWR-based data fetching.
Works With Any React Framework
This package works with any React-based framework:
- ✅ Create React App (CRA)
- ✅ Vite + React
- ✅ TanStack Start (React Router)
- ✅ Remix (client-side)
- ✅ Astro (React islands)
- ✅ Any other React framework
For Next.js, use @pubflow/nextjs instead for SSR support and API routes.
Installation ​
npm install @pubflow/core @pubflow/react swrQuick Start ​
import { PubflowProvider, useAuth, useBridgeQuery } from '@pubflow/react';
function App() {
return (
<PubflowProvider url="https://your-backend.com">
<Dashboard />
</PubflowProvider>
);
}
function Dashboard() {
const { user, logout } = useAuth();
const { data, error, isLoading } = useBridgeQuery('/api/users');
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<h1>Welcome, {user?.name}!</h1>
<button onClick={logout}>Logout</button>
<ul>
{data.map((user: any) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
);
}Provider ​
PubflowProvider ​
Wrap your app with PubflowProvider to configure Flowfull Clients.
import { PubflowProvider } from '@pubflow/react';
<PubflowProvider
url="https://your-backend.com"
instanceId="default"
onAuthError={(error) => console.error('Auth error:', error)}
onSessionExpired={() => console.log('Session expired')}
>
<App />
</PubflowProvider>Props ​
| Prop | Type | Required | Description |
|---|---|---|---|
url | string | Yes | Your Flowfull backend URL |
instanceId | string | No | Instance ID for multi-instance support |
onAuthError | (error: Error) => void | No | Called when authentication errors occur |
onSessionExpired | () => void | No | Called when session expires |
children | ReactNode | Yes | Your app components |
Hooks ​
useAuth() ​
Access authentication state and methods.
import { useAuth } from '@pubflow/react';
function LoginForm() {
const {
user,
isAuthenticated,
isLoading,
error,
login,
logout,
register,
} = useAuth();
const handleLogin = async () => {
try {
await login({
email: 'user@example.com',
password: 'password123',
});
} catch (err) {
console.error('Login failed:', err);
}
};
return (
<div>
{isAuthenticated ? (
<>
<p>Welcome, {user?.name}!</p>
<button onClick={logout}>Logout</button>
</>
) : (
<button onClick={handleLogin} disabled={isLoading}>
Login
</button>
)}
</div>
);
}Return Value ​
{
user: User | null;
isAuthenticated: boolean;
isLoading: boolean;
error: Error | null;
login: (credentials: LoginCredentials) => Promise<User>;
register: (data: RegisterData) => Promise<User>;
logout: () => Promise<void>;
refreshSession: () => Promise<void>;
}useBridgeQuery() ​
Fetch data from your Flowfull backend with SWR.
import { useBridgeQuery } from '@pubflow/react';
function UserList() {
const { data, error, isLoading, mutate } = useBridgeQuery('/api/users');
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<button onClick={() => mutate()}>Refresh</button>
<ul>
{data.map((user: any) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
);
}Parameters ​
useBridgeQuery<T>(
path: string,
options?: {
params?: Record<string, any>;
swrOptions?: SWRConfiguration;
}
)Return Value ​
{
data: T | undefined;
error: Error | undefined;
isLoading: boolean;
isValidating: boolean;
mutate: () => Promise<void>;
}useBridgeMutation() ​
Create, update, or delete data with optimistic updates.
import { useBridgeMutation } from '@pubflow/react';
function CreateUserForm() {
const { trigger, isMutating, error } = useBridgeMutation('/api/users', 'POST');
const [name, setName] = useState('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
const newUser = await trigger({ name });
console.log('User created:', newUser);
setName('');
} catch (err) {
console.error('Failed to create user:', err);
}
};
return (
<form onSubmit={handleSubmit}>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Name"
/>
<button type="submit" disabled={isMutating}>
{isMutating ? 'Creating...' : 'Create User'}
</button>
{error && <p>Error: {error.message}</p>}
</form>
);
}Parameters ​
useBridgeMutation<T>(
path: string,
method: 'POST' | 'PUT' | 'PATCH' | 'DELETE',
options?: {
revalidate?: string[]; // Paths to revalidate after mutation
optimisticData?: (current: any, data: any) => any;
}
)Return Value ​
{
trigger: (data?: any) => Promise<T>;
isMutating: boolean;
error: Error | undefined;
reset: () => void;
}useBridgeCrud() ​
Complete CRUD operations for a resource.
import { useBridgeCrud } from '@pubflow/react';
function UserManager() {
const {
items,
isLoading,
error,
create,
update,
remove,
refresh,
} = useBridgeCrud('/api/users');
const handleCreate = async () => {
await create({ name: 'New User' });
};
const handleUpdate = async (id: string) => {
await update(id, { name: 'Updated Name' });
};
const handleDelete = async (id: string) => {
await remove(id);
};
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<button onClick={handleCreate}>Create User</button>
<button onClick={refresh}>Refresh</button>
<ul>
{items.map((user: any) => (
<li key={user.id}>
{user.name}
<button onClick={() => handleUpdate(user.id)}>Edit</button>
<button onClick={() => handleDelete(user.id)}>Delete</button>
</li>
))}
</ul>
</div>
);
}Return Value ​
{
items: T[];
isLoading: boolean;
error: Error | undefined;
create: (data: Partial<T>) => Promise<T>;
update: (id: string, data: Partial<T>) => Promise<T>;
remove: (id: string) => Promise<void>;
refresh: () => Promise<void>;
}useBridgeApi() ​
Direct access to the API client for custom requests.
import { useBridgeApi } from '@pubflow/react';
function CustomComponent() {
const api = useBridgeApi();
const handleCustomRequest = async () => {
const response = await api.post('/api/custom-endpoint', {
custom: 'data',
});
console.log('Response:', response);
};
return <button onClick={handleCustomRequest}>Custom Request</button>;
}Components ​
BridgeView ​
Display data from an API endpoint with automatic loading and error states.
import { BridgeView } from '@pubflow/react';
<BridgeView
endpoint="/api/users"
render={(data) => (
<ul>
{data.map((user: any) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
)}
loading={<div>Loading users...</div>}
error={(error) => <div>Error: {error.message}</div>}
/>Props ​
| Prop | Type | Required | Description |
|---|---|---|---|
endpoint | string | Yes | API endpoint to fetch from |
render | (data: T) => ReactNode | Yes | Render function for data |
loading | ReactNode | No | Loading state component |
error | (error: Error) => ReactNode | No | Error state component |
params | Record<string, any> | No | Query parameters |
BridgeTable ​
Display data in a table with sorting, filtering, and pagination.
import { BridgeTable } from '@pubflow/react';
<BridgeTable
endpoint="/api/users"
columns={[
{ key: 'name', label: 'Name', sortable: true },
{ key: 'email', label: 'Email', sortable: true },
{ key: 'created_at', label: 'Created', sortable: true },
]}
onRowClick={(user) => console.log('Clicked:', user)}
searchable
pagination
/>Props ​
| Prop | Type | Required | Description |
|---|---|---|---|
endpoint | string | Yes | API endpoint to fetch from |
columns | Column[] | Yes | Table columns configuration |
onRowClick | (row: T) => void | No | Row click handler |
searchable | boolean | No | Enable search |
pagination | boolean | No | Enable pagination |
pageSize | number | No | Items per page (default: 10) |
BridgeForm ​
Form component with automatic validation and API integration.
import { BridgeForm } from '@pubflow/react';
import { z } from 'zod';
const userSchema = z.object({
name: z.string().min(2, 'Name must be at least 2 characters'),
email: z.string().email('Invalid email address'),
age: z.number().min(18, 'Must be at least 18 years old'),
});
<BridgeForm
endpoint="/api/users"
method="POST"
schema={userSchema}
onSuccess={(data) => console.log('User created:', data)}
onError={(error) => console.error('Error:', error)}
fields={[
{ name: 'name', label: 'Name', type: 'text' },
{ name: 'email', label: 'Email', type: 'email' },
{ name: 'age', label: 'Age', type: 'number' },
]}
submitLabel="Create User"
/>Props ​
| Prop | Type | Required | Description |
|---|---|---|---|
endpoint | string | Yes | API endpoint to submit to |
method | 'POST' | 'PUT' | 'PATCH' | Yes | HTTP method |
schema | ZodSchema | No | Zod validation schema |
fields | Field[] | Yes | Form fields configuration |
onSuccess | (data: T) => void | No | Success callback |
onError | (error: Error) => void | No | Error callback |
submitLabel | string | No | Submit button label |
initialValues | Record<string, any> | No | Initial form values |
BridgeList ​
Display a list of items with infinite scroll and pull-to-refresh.
import { BridgeList } from '@pubflow/react';
<BridgeList
endpoint="/api/users"
renderItem={(user) => (
<div key={user.id}>
<h3>{user.name}</h3>
<p>{user.email}</p>
</div>
)}
emptyMessage="No users found"
infiniteScroll
pullToRefresh
/>Props ​
| Prop | Type | Required | Description |
|---|---|---|---|
endpoint | string | Yes | API endpoint to fetch from |
renderItem | (item: T) => ReactNode | Yes | Render function for each item |
emptyMessage | string | No | Message when list is empty |
infiniteScroll | boolean | No | Enable infinite scroll |
pullToRefresh | boolean | No | Enable pull-to-refresh |
pageSize | number | No | Items per page (default: 20) |
OfflineIndicator ​
Display connection status indicator.
import { OfflineIndicator } from '@pubflow/react';
<OfflineIndicator
position="top"
message="You are offline"
style={{ background: '#ff0000', color: '#fff' }}
/>AdvancedFilter ​
Advanced filtering component for data tables.
import { AdvancedFilter } from '@pubflow/react';
<AdvancedFilter
fields={[
{ name: 'name', label: 'Name', type: 'text' },
{ name: 'status', label: 'Status', type: 'select', options: ['active', 'inactive'] },
{ name: 'created_at', label: 'Created', type: 'date' },
]}
onFilter={(filters) => console.log('Filters:', filters)}
/>Examples ​
Complete CRUD Example ​
import { PubflowProvider, useBridgeCrud, BridgeForm } from '@pubflow/react';
import { useState } from 'react';
import { z } from 'zod';
const userSchema = z.object({
name: z.string().min(2),
email: z.string().email(),
});
function UserManagement() {
const { items, isLoading, create, update, remove } = useBridgeCrud('/api/users');
const [editing, setEditing] = useState<string | null>(null);
if (isLoading) return <div>Loading...</div>;
return (
<div>
<h2>Create User</h2>
<BridgeForm
endpoint="/api/users"
method="POST"
schema={userSchema}
fields={[
{ name: 'name', label: 'Name', type: 'text' },
{ name: 'email', label: 'Email', type: 'email' },
]}
onSuccess={() => console.log('User created')}
/>
<h2>Users</h2>
<ul>
{items.map((user: any) => (
<li key={user.id}>
{editing === user.id ? (
<BridgeForm
endpoint={`/api/users/${user.id}`}
method="PUT"
schema={userSchema}
fields={[
{ name: 'name', label: 'Name', type: 'text' },
{ name: 'email', label: 'Email', type: 'email' },
]}
initialValues={user}
onSuccess={() => setEditing(null)}
/>
) : (
<>
{user.name} - {user.email}
<button onClick={() => setEditing(user.id)}>Edit</button>
<button onClick={() => remove(user.id)}>Delete</button>
</>
)}
</li>
))}
</ul>
</div>
);
}
function App() {
return (
<PubflowProvider url="https://your-backend.com">
<UserManagement />
</PubflowProvider>
);
}TypeScript Support ​
All hooks and components are fully typed:
import { useBridgeQuery } from '@pubflow/react';
interface User {
id: string;
name: string;
email: string;
}
function UserList() {
const { data, error, isLoading } = useBridgeQuery<User[]>('/api/users');
// data is typed as User[] | undefined
// TypeScript will catch errors
}Next Steps ​
- Authentication Guide - Learn about authentication
- API Calls Guide - Master the Bridge API
- Forms Guide - Work with forms
- Examples - See more examples