Integrate DatoCMS with React

    Building a single-page application using React and GraphQL is probably one of the fastest way to go live with a CMS-backed website.

    With the globally-distributed CDN serving the Content Delivery API of DatoCMS you can serve directly content to your end users without an intermediate server. You just maintain and host a static frontend application and we deal with the rest!

    Fetching content from our GraphQL API

    To fetch GraphQL content with React from DatoCMS there are many options. Some of the most powerful GraphQL clients are:

    • Apollo, which offers the @apollo/react-hooks package to make GraphQL queries using React hooks;
    • urql, which just like Apollo acts as primary data layer and can handle content-heavy pages through "document caching";

    But since you're only going to make simple queries to our API — with no mutations involved — we suggest to use a much lighter solution like graphql-hooks (2.8kB gzipped) or graphql-react.

    You can even use pure JS clients like graphql-request and use them inside a React useEffect hook.

    Our marketplace features many different demo projects, with different GraphQL libraries, so you can learn and get started easily:

    Quick start using graphql-hooks

    First create a new React application using React Create App:

    npx create-react-app my-app

    Then enter inside the my-app directory, install the graphql-hooks package, and start the development server:

    cd my-app
    yarn add graphql-hooks
    yarn start

    First you'll need to create a GraphQL client pointing to one of the GraphQL Content Delivery API endpoints and wrap your app with the provider:

    // src/index.js
    import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.css';
    import App from './App';
    import * as serviceWorker from './serviceWorker';
    import { GraphQLClient, ClientContext } from 'graphql-hooks'
    const client = new GraphQLClient({
    url: "https://graphql.datocms.com/",
    headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    }
    });
    ReactDOM.render(
    <React.StrictMode>
    <ClientContext.Provider value={client}>
    <App />
    </ClientContext.Provider>
    </React.StrictMode>,
    document.getElementById("root")
    );
    serviceWorker.unregister();

    Make sure you replace YOUR_API_TOKEN with an actual API token of your DatoCMS project. You can create a new one under "Settings > API Tokens".

    Next, go to src/App.js and use the useQuery hook to perform your GrapQL query:

    import React from "react";
    import { useQuery } from "graphql-hooks";
    import "./App.css";
    const HOMEPAGE_QUERY = `query HomePage($limit: IntType) {
    allBlogPosts(first: $limit) {
    title
    }
    }`;
    function App() {
    const { loading, error, data } = useQuery(HOMEPAGE_QUERY, {
    variables: {
    limit: 10
    }
    });
    if (loading) return "Loading...";
    if (error) return "Something Bad Happened";
    return (
    <div className="App">
    {JSON.stringify(data)}
    </div>
    );
    }
    export default App;

    The HOMEPAGE_QUERY is the GraphQL query, and of course it depends on the models available in your define in your specific DatoCMS project.

    You can learn everything you need regarding how to build GraphQL queries on our Content Delivery API documentation.

    Accessing draft/updated content

    If you have draft/published mode enabled on some of your models, you can use the https://graphql.datocms.com/preview endpoint to access records at their latest version available, instead of the currently published.

    Both endpoints offer exactly the same queries, the only thing that will change will be the returned content.

    const client = new GraphQLClient({
    url: "https://graphql.datocms.com/preview",
    headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    }
    });

    Loading responsive, progressive images from DatoCMS

    One of the mayor advantages of using DatoCMS instead of any other content management systems is its responsiveImage query, which will return pre-computed image attributes that will help you setting up responsive images in your frontend without any additional manipulation.

    To make it even easier to offer responsive, progressive, lazy-loaded images on your projects, we released a package called react-datocms that exposes an <Image /> component and pairs perfectly with the responsiveImage query:

    To take advantage of it, install the react-datocms package:

    yarn add react-datocms

    Then, inside your page, feed content coming from a responsiveImage query directly into the <Image /> component:

    import React from "react";
    import { useQuery } from "graphql-hooks";
    import { Image } from 'react-datocms';
    import "./App.css";
    const HOMEPAGE_QUERY = `query HomePage($limit: IntType) {
    allBlogPosts(first: $limit) {
    title
    coverImage {
    responsiveImage(imgixParams: { fit: crop, w: 300, h: 300, auto: format }) {
    srcSet
    webpSrcSet
    sizes
    src
    width
    height
    aspectRatio
    alt
    title
    base64
    }
    }
    }
    }`;
    function App() {
    const { loading, error, data } = useQuery(HOMEPAGE_QUERY, {
    variables: {
    limit: 10
    }
    });
    if (loading) return "Loading...";
    if (error) return "Something Bad Happened";
    return (
    <div className="App">
    {data.allBlogPosts.map(blogPost => (
    <article>
    <Image data={blogPost.coverImage.responsiveImage} />
    <h6>{blogPost.title}</h6>
    </article>
    ))}
    </div>
    );
    }
    export default App;

    SEO management

    Similarly to what we offer with responsive images, our GraphQL API also offers a way to fetch pre-computed SEO meta tags based on the content you insert inside DatoCMS.

    You can easily use this information inside your React app with the help of:

    Here's a sample of the meta tags you can automatically generate:

    <title>DatoCMS Blog - DatoCMS</title>
    <meta property="og:title" content="DatoCMS Blog" />
    <meta name="twitter:title" content="DatoCMS Blog" />
    <meta name="description" content="Lorem ipsum..." />
    <meta property="og:description" content="Lorem ipsum..." />
    <meta name="twitter:description" content="Lorem ipsum..." />
    <meta property="og:image" content="https://www.datocms-assets.com/..." />
    <meta property="og:image:width" content="2482" />
    <meta property="og:image:height" content="1572" />
    <meta name="twitter:image" content="https://www.datocms-assets.com/..." />
    <meta property="og:locale" content="en" />
    <meta property="og:type" content="website" />
    <meta property="og:site_name" content="DatoCMS" />
    <meta property="article:modified_time" content="2020-03-06T15:07:14Z" />
    <meta name="twitter:card" content="summary" />
    <meta name="twitter:site" content="@datocms" />
    <link sizes="16x16" type="image/png" rel="icon" href="https://www.datocms-assets.com/..." />
    <link sizes="32x32" type="image/png" rel="icon" href="https://www.datocms-assets.com/..." />
    <link sizes="96x96" type="image/png" rel="icon" href="https://www.datocms-assets.com/..." />
    <link sizes="192x192" type="image/png" rel="icon" href="https://www.datocms-assets.com/..." />

    To do that, first install both react-helmet and the react-datocms package:

    yarn add react-helmet react-datocms

    Then, inside your page, feed content coming from a faviconMetaTags or _seoMetaTags query directly into the renderMetaTags function:

    import React from "react";
    import { useQuery } from "graphql-hooks";
    import { renderMetaTags } from "react-datocms";
    import { Helmet } from "react-helmet";
    import "./App.css";
    const HOMEPAGE_QUERY = `
    {
    site: _site {
    favicon: faviconMetaTags {
    attributes
    content
    tag
    }
    }
    blog {
    seo: _seoMetaTags {
    attributes
    content
    tag
    }
    }
    }`;
    function App() {
    const { loading, error, data } = useQuery(HOMEPAGE_QUERY);
    if (loading) return "Loading...";
    if (error) return "Something Bad Happened";
    return (
    <div className="App">
    <Helmet>
    {renderMetaTags(data.blog.seo.concat(data.site.favicon))}
    </Helmet>
    {/* ... */}
    </div>
    );
    }
    export default App;

    Real-time streaming updates of content

    Live updates can be extremely useful both for content editors and the regular visitors of your app/website:

    • Content-editors in Preview Mode can see drafts directly in the production website, without having to refresh the page;
    • Visitors can immediately see new content as it gets published, allowing all kinds of real-time interactions with your website/app (ie. live-news coverage).

    Inside a React project, it's extremely easy to use our Real-time Updates API to perform such changes, as it only involves replacing the useQuery hook with a the useQuerySubscription hook that the react-datocms package makes available:

    import React from "react";
    import { useQuerySubscription } from "react-datocms";
    const App: React.FC = () => {
    const { status, error, data } = useQuerySubscription({
    query: `
    query AppQuery($first: IntType) {
    allBlogPosts {
    slug
    title
    }
    }`,
    variables: { first: 10 },
    token: "YOUR_API_TOKEN",
    });
    const statusMessage = {
    connecting: "Connecting to DatoCMS...",
    connected: "Connected to DatoCMS, receiving live updates!",
    closed: "Connection closed",
    };
    return (
    <div>
    <p>Connection status: {statusMessage[status]}</p>
    {error && (
    <div>
    <h1>Error: {error.code}</h1>
    <div>{error.message}</div>
    {error.response && (
    <pre>{JSON.stringify(error.response, null, 2)}</pre>
    )}
    </div>
    )}
    {data && (
    <ul>
    {data.allBlogPosts.map((blogPost) => (
    <li key={blogPost.slug}>{blogPost.title}</li>
    ))}
    </ul>
    )}
    </div>
    );
    };
    export default App;