React Router

React Router + DatoCMS Overview

React Router is the routing standard of the React ecosystem, and since version 7 it also ships a full-stack framework mode: server rendering, nested routes, data loading, actions and type-safe route modules, all built on top of Vite. It lets you get started without having to write much boilerplate code, and with a set of sane defaults from which you can build upon.

React Router fully supports edge functions and advanced caching mechanisms, and React Router projects can be deployed on many different hostings, such as Netlify, Vercel and Cloudflare Workers. See the deploying guide for the full list of options.

DatoCMS is the perfect companion to React Router since it offers content, images, and videos on a globally-distributed CDN. With this combo, you can have an infinitely scalable website, ready to handle prime-time TV traffic spikes, at a fraction of the regular cost.

Coming from Remix?

React Router v7 in framework mode is the direct continuation of Remix v2: same route modules, same loader and action functions, same progressive enhancement. The main difference is that imports moved from @remix-run/* to react-router. If you have an existing Remix v2 project, follow the official upgrade guide.

Be aware that Remix v3 is a different, React-less framework, with no migration path from Remix v2. This guide does not cover it.

Our marketplace features different demo projects you can learn from and get started easily. The following one is built with Remix, but every pattern in it applies to React Router as well:

Fetching content from our GraphQL API

First, use the React Router wizard to set up a new project. Read more about your options on the React Router docs.

Terminal window
npx create-react-router@latest

The way you fetch content from external sources in React Router is by exporting a loader function from your route modules. Whatever the loader returns is handed over to the React component through its loaderData prop:

app/routes/home.tsx
import type { Route } from './+types/home';
export async function loader() {
return { foo: 'bar' };
}
export default function Homepage({ loaderData }: Route.ComponentProps) {
const { foo } = loaderData;
// ...
}

Route modules are then wired up in app/routes.ts, which is where you declare the URL each of them responds to:

app/routes.ts
import { type RouteConfig, index } from '@react-router/dev/routes';
export default [index('routes/home.tsx')] satisfies RouteConfig;

Inside the loader function, we can use any Node.JS GraphQL client (or HTTP client, really) to fetch content from the Content Delivery API of DatoCMS.

Let's start by installing @datocms/cda-client, a lightweight, TypeScript-ready package that offers various helpers around the native Fetch API to perform GraphQL requests towards DatoCMS Content Delivery API:

Terminal window
npm install --save @datocms/cda-client
Pro tip: Top 5 JavaScript GraphQL Client Libraries

Our @datocms/cda-client is not the only option. This blog post ranks the best JavaScript GraphQL client libraries, helping you choose the right tool based on your project’s specific needs and ensuring efficient and optimized GraphQL data fetching.

We can now create a function we can use in all of our components that need to fetch content from DatoCMS: Create a new directory called lib inside app, and inside of it, add a file called datocms.js:

app/lib/datocms.js
import { executeQuery } from '@datocms/cda-client';
export const load = (query, options) => {
return executeQuery(query, {
...options,
token: process.env.DATOCMS_READONLY_TOKEN,
environment: process.env.DATOCMS_ENVIRONMENT,
});
}

We want to store inside environment variables both the API token and the name of the DatoCMS environment we want to fetch content from to hide them from the code, and so that we'll be able to modify them later without touching the code. React Router runs on Vite, so a .env file at the root of your project is all you need during development. Loaders and actions only ever run on the server, so they can safely read those secrets from process.env.

To create an API token for a DatoCMS project, go to Settings > API Tokens section of your DatoCMS backend. Make sure to only give it permissions to access the (read-only) Content Delivery API.

It's time to use our function in a real page! Open up app/routes/home.tsx, which is the route that renders the homepage, and define the loader function and a basic page component:

import type { Route } from './+types/home';
import { load } from '~/lib/datocms';
const HOMEPAGE_QUERY = `query HomePage($limit: IntType) {
posts: allBlogPosts(first: $limit) {
title
}
}`;
export async function loader() {
return load(HOMEPAGE_QUERY, {
variables: { limit: 10 },
});
}
export default function Home({ loaderData }: Route.ComponentProps) {
const { posts } = loaderData;
return <div>{JSON.stringify(posts, null, 2)}</div>;
}

The HOMEPAGE_QUERY is the GraphQL query, and of course it depends on the models available in your specific DatoCMS project. You can learn everything you need regarding how to build GraphQL queries on our Content Delivery API documentation.

For more information on what to do next, we recommend reading the next sections of this integration guide!

Last updated: