React Router v7
React Router v7 can be used to handle functionalities traditionally associated with a backend, effectively blurring the lines between client-side and server-side development. This is achieved through its new “framework mode,” which incorporates features from the powerful full-stack framework, Remix. While it doesn’t replace the need for a dedicated backend in all scenarios, it offers a robust solution for building full-stack React applications with a unified routing system.
The key to React Router v7’s backend capabilities lies in its data loading and mutation features, primarily through
loader
andaction
functions. These functions are defined on your routes and execute on the server, allowing you to fetch data and handle form submissions before your components even render on the client.
How to Use React Router v7 for Backend-like Functionalities
Section titled “How to Use React Router v7 for Backend-like Functionalities”To leverage these features, you’ll need to be using React Router in its “framework mode,” which is the default when setting up a new project with the Vite plugin for React Router.
1. Data Fetching with loader
Functions
Section titled “1. Data Fetching with loader Functions”The loader
function is a server-side function that you can export from your route modules. It’s responsible for fetching the data required for that route.
import { useLoaderData } from "react-router-dom";
export async function loader() { const response = await fetch( "[https://api.example.com/posts](https://api.example.com/posts)", ); const posts = await response.json(); return { posts };}
export default function Posts() { const { posts } = useLoaderData();
return ( <ul> {posts.map((post) => ( <li key={post.id}>{post.title}</li> ))} </ul> );}
In this example, before the Posts
component is rendered, the loader
function will execute on the server, fetch the posts from an API, and make the data available to the component via the useLoaderData
hook.
2. Handling Data Mutations with action
Functions
Section titled “2. Handling Data Mutations with action Functions”The action
function is another server-side function that handles data mutations, typically from form submissions. It receives the request object, allowing you to access form data.
import { redirect, Form } from "react-router-dom";
// This is a placeholder for your actual data creation logicasync function createPost(data) { // e.g., await db.posts.create({ data }); console.log("Creating post:", data);}
export async function action({ request }) { const formData = await request.formData(); const title = formData.get("title"); const content = formData.get("content");
await createPost({ title, content });
return redirect("/posts");}
export default function NewPost() { return ( <Form method="post"> <input type="text" name="title" placeholder="Post Title" /> <textarea name="content" placeholder="Write your post..." /> <button type="submit">Create Post</button> </Form> );}
When the form in the NewPost
component is submitted, the action
function is invoked on the server. It processes the form data, creates a new post, and then redirects the user to the posts page.
3. Server-Side Rendering (SSR)
Section titled “3. Server-Side Rendering (SSR)”By default, when using the framework mode, React Router v7 enables Server-Side Rendering (SSR). This means the initial page load is rendered on the server, providing faster perceived performance and better SEO.