Integrating MeshBase with React
Build powerful React applications with MeshBase as your content backend. Hooks, Context API, and modern React patternsβall included.
Why MeshBase + React?
π£Hook-Based API
Custom React hooks for data fetching. Clean, reusable patterns that feel natural in React.
β‘Framework Agnostic
Works with Create React App, Vite, or any React setup. No build tool requirements.
πReal-Time Updates
Combine with React Query or SWR for automatic cache management and real-time updates.
π―TypeScript Ready
Full TypeScript support. Type-safe content fetching with auto-completion.
What You'll Need
- βReact 16.8+ project (hooks support required)
- βA MeshBase account with content types defined
- βYour MeshBase public API key
Quick Start
The simplest way to fetch MeshBase content in React.
1. Set up environment variables
Create .env (or .env.local for CRA):
REACT_APP_MESHBASE_API_URL=https://api.meshbase.io/v1
REACT_APP_MESHBASE_API_KEY=your-public-api-key-hereFor Vite, use VITE_ prefix instead of REACT_APP_
2. Create a custom hook
Create hooks/useMeshBase.js:
import { useState, useEffect } from 'react';
const API_URL = process.env.REACT_APP_MESHBASE_API_URL;
const API_KEY = process.env.REACT_APP_MESHBASE_API_KEY;
export function useMeshBase(endpoint) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchData() {
try {
const response = await fetch(`${API_URL}${endpoint}`, {
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
});
if (!response.ok) throw new Error('Failed to fetch');
const json = await response.json();
setData(json.data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}
fetchData();
}, [endpoint]);
return { data, loading, error };
}3. Use it in your components
import { useMeshBase } from './hooks/useMeshBase';
function BlogList() {
const { data: posts, loading, error } = useMeshBase('/blog-posts');
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return (
<div className="blog-list">
{posts?.map(post => (
<article key={post.id}>
<h2>{post.title}</h2>
<p>{post.excerpt}</p>
<a href={`/blog/${post.id}`}>Read more</a>
</article>
))}
</div>
);
}
export default BlogList;You're Done!
That's all you need! Your React app now fetches content from MeshBase. The custom hook handles loading states, errors, and data fetching automatically.
TypeScript Version
Using TypeScript? Here's a type-safe version.
Create hooks/useMeshBase.ts:
import { useState, useEffect } from 'react';
const API_URL = process.env.REACT_APP_MESHBASE_API_URL;
const API_KEY = process.env.REACT_APP_MESHBASE_API_KEY;
interface UseMeshBaseResult<T> {
data: T | null;
loading: boolean;
error: string | null;
}
export function useMeshBase<T>(endpoint: string): UseMeshBaseResult<T[]> {
const [data, setData] = useState<T[] | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
async function fetchData() {
try {
const response = await fetch(`${API_URL}${endpoint}`, {
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
});
if (!response.ok) throw new Error('Failed to fetch');
const json = await response.json();
setData(json.data);
} catch (err) {
setError(err instanceof Error ? err.message : 'Unknown error');
} finally {
setLoading(false);
}
}
fetchData();
}, [endpoint]);
return { data, loading, error };
}
// Typed helper hooks
export function useBlogPosts() {
return useMeshBase<BlogPost>('/blog-posts');
}
// Define your types
export interface BlogPost {
id: string;
title: string;
excerpt: string;
content: string;
coverImage?: string;
publishedAt: string;
}Usage with types:
import { useBlogPosts } from './hooks/useMeshBase';
function BlogList() {
const { data: posts, loading, error } = useBlogPosts();
// TypeScript knows posts is BlogPost[] | null
// Auto-completion works!
return (
<div>
{posts?.map(post => (
<article key={post.id}>
<h2>{post.title}</h2> {/* β Type-safe */}
</article>
))}
</div>
);
}React Query Integration (Recommended)
For production apps, React Query provides caching, refetching, and more.
Install React Query
npm install @tanstack/react-querySet up QueryClient
Wrap your app with QueryClientProvider:
// App.jsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<YourApp />
</QueryClientProvider>
);
}Create API helpers
Create lib/meshbase.js:
const API_URL = process.env.REACT_APP_MESHBASE_API_URL;
const API_KEY = process.env.REACT_APP_MESHBASE_API_KEY;
async function fetchFromMeshBase(endpoint) {
const response = await fetch(`${API_URL}${endpoint}`, {
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
});
if (!response.ok) throw new Error('Failed to fetch');
const json = await response.json();
return json.data;
}
export const meshbaseAPI = {
getBlogPosts: () => fetchFromMeshBase('/blog-posts'),
getBlogPost: (id) => fetchFromMeshBase(`/blog-posts/${id}`),
getProducts: () => fetchFromMeshBase('/products'),
};Use with React Query hooks
import { useQuery } from '@tanstack/react-query';
import { meshbaseAPI } from './lib/meshbase';
function BlogList() {
const { data: posts, isLoading, error } = useQuery({
queryKey: ['blog-posts'],
queryFn: meshbaseAPI.getBlogPosts,
staleTime: 60000, // Consider fresh for 1 minute
});
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
{posts?.map(post => (
<article key={post.id}>
<h2>{post.title}</h2>
<p>{post.excerpt}</p>
</article>
))}
</div>
);
}Why React Query?
React Query gives you:
- Automatic caching and cache invalidation
- Background refetching
- Request deduplication
- Pagination and infinite scroll support
Context API Pattern
Share MeshBase data across your app with Context.
Create context/ContentContext.jsx:
import { createContext, useContext, useState, useEffect } from 'react';
import { meshbaseAPI } from '../lib/meshbase';
const ContentContext = createContext();
export function ContentProvider({ children }) {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
meshbaseAPI.getBlogPosts()
.then(setPosts)
.finally(() => setLoading(false));
}, []);
return (
<ContentContext.Provider value={{ posts, loading }}>
{children}
</ContentContext.Provider>
);
}
export function useContent() {
const context = useContext(ContentContext);
if (!context) throw new Error('useContent must be used within ContentProvider');
return context;
}Wrap your app:
// App.jsx
import { ContentProvider } from './context/ContentContext';
function App() {
return (
<ContentProvider>
<YourApp />
</ContentProvider>
);
}Use anywhere in your app:
import { useContent } from './context/ContentContext';
function BlogList() {
const { posts, loading } = useContent();
if (loading) return <div>Loading...</div>;
return (
<div>
{posts.map(post => (
<article key={post.id}>
<h2>{post.title}</h2>
</article>
))}
</div>
);
}Next Steps
- βUsing Next.js?
Check out our Next.js integration guide
- βHandle images and media
Upload and serve media files
- βExplore the full API
Filtering, sorting, pagination, and more