Better Blog

React

React SPA client-side rendering with React DOM Router

Render all blog routes under /posts/* using client-side data fetching.

1) main.tsx

import { createRoot } from 'react-dom/client';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { Provider } from './providers';
import BlogEntryPage from './BlogEntryPage';

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <BrowserRouter>
    <Provider>
      <Routes>
        <Route path="/posts/*" element={<BlogEntryPage />} />
      </Routes>
    </Provider>
  </BrowserRouter>
)

2) BlogEntryPage.tsx

import { useLocation } from "react-router-dom"
import { BlogRouterPage } from "better-blog/client"

export default function BlogEntryPage() {
  const location = useLocation()

  return (
    <main >
      <BlogRouterPage path={location.pathname} />
    </main>
  )
}

3) providers.tsx

import { QueryClientProvider } from "@tanstack/react-query";
import type { ReactNode } from "react";
import { NavLink, useNavigate } from "react-router-dom"
import { BetterBlogContextProvider } from "better-blog/client";
import type { ComponentsContextValue, BlogDataProvider, getDefaultQueryClient } from "better-blog";
import { ThemeProvider } from "./theme-provider";


// React router DOM link and simple image
const components: ComponentsContextValue = {
  Link: ({ href, children, className }) => (
    <NavLink to={href.replace('/posts', '/blog')} className={className}>
      {children}
    </NavLink>
  ),
  Image: ({ src, alt, className }) => (
    <img src={src} alt={alt} className={className} />
  ),
};

// Implement your data provider here
const clientBlogConfig: BlogDataProvider = {
  ...
};

export function Provider({ children }: { children: ReactNode }) {
  const queryClient = getQueryClient();
  const navigate = useNavigate()

  return (
    <QueryClientProvider client={queryClient}>
      <ThemeProvider>
        <BetterBlogContextProvider
          localization={{
            BLOG_LIST_TITLE: "Blog Posts",
          }}
          clientConfig={clientBlogConfig}
          components={components}
          navigate={navigate}
          basePath="/blog"
          adminUiOptions={{
            canCreate:true,
            canUpdate:true,
            canDelete:true
          }}
          uploadImage={async (file) => {
            console.log("uploadImage", file);
            // implement your own image upload logic here
            return "https://via.placeholder.com/150/png";
          }}
        >
          {children}
        </BetterBlogContextProvider>
      </ThemeProvider>
    </QueryClientProvider>
  );
}