βš›οΈFramework Integration

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-here

For 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-query

Set 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