react-datocms

repository·master·Indexed 41 days ago

https://github.com/datocms/react-datocms

A library of React components and hooks for DatoCMS integration. Version 8.1.2 provides tools for rendering structured text, handling responsive images via <RSCImage /> and <Image />, managing video with <VideoPlayer />, and implementing Visual Editing features using the <ContentLink /> component and useContentLink() hook.

Tokens
29.1K
Snippets
71
Records
98
Agent score
46%

What's inside react-datocms

  1. Overview of react-datocms features

    master

    The react-datocms package provides specialized components and hooks designed to work with DatoCMS's GraphQL Content Delivery API and Real-time Updates API. Key features include:

    • Image Handling: <RSCImage /> and <Image /> components for responsive and progressive images.
    • Structured Text: The <StructuredText /> component for rendering complex content structures.
    • Media: The <VideoPlayer /> component for video content.
    • Visual Editing: <ContentLink /> component and useContentLink() hook for click-to-edit overlays.
    • Real-time Updates: useQuerySubscription() hook for live content updates.
    • Site Search: useSiteSearch() hook to render a DatoCMS Site Search form widget.
    • SEO & Meta Tags: renderMetaTags() and other helpers for social share, SEO, and Favicon meta tags.
  2. Understand the returned data from useSiteSearch

    master

    The hook returns an object containing state, error, and data.

    Loading State: If both error and data are null, the hook is currently loading results.

    State Object: Reflects current form state and provides setters that trigger new API requests:

    • query: current search string
    • setQuery(newQuery: string): updates the query
    • locale: current locale
    • setLocale(newLocale: string): updates the locale
    • page: current page number
    • setPage(newPage: number): updates the page

    Data Object: Contains the search results:

    • pageResults: Array of { id, title, bodyExcerpt, url, raw }
    • totalResults: Total number of matches found
    • totalPages: Total number of pages available
  3. Prepare DatoCMS GraphQL queries for meta tags

    master

    The meta tag utilities expect an array of SeoOrFaviconTag objects. These are returned by the following DatoCMS GraphQL queries:

    • _seoMetaTags: Available on any record type for SEO data.
    • faviconMetaTags: Available on the global _site object for favicon data.

    Each tag object contains attributes, content, and tag fields.

    query {
      page: homepage {
        title
        seo: _seoMetaTags {
          attributes
          content
          tag
        }
      }
    
      site: _site {
        favicon: faviconMetaTags {
          attributes
          content
          tag
        }
      }
    }
  4. Implement live real-time updates with `useQuerySubscription`

    master

    The useQuerySubscription hook allows you to implement client-side updates of your page as soon as content changes in DatoCMS. It uses the DatoCMS Real-time Updates API via Server-Sent Events (SSE) to receive updated query results in real-time and handles automatic reconnection during network failures.

    It is compatible with vanilla React, Next.js, and other React-based solutions, and is fully TypeScript-ready.

    import { useQuerySubscription } from 'react-datocms';
    
    const { data, error, status } = useQuerySubscription({
      query: `query MyQuery { ... }`,
      token: 'YOUR_API_TOKEN',
      // ... other options
    });
  5. Compare `<RSCImage />` and `<Image />`

    master

    Both components work with DatoCMS's responsiveImage GraphQL query to optimize image loading, but they serve different architectural needs:

    <RSCImage /> (React Server Component)

    • Rendering: Rendered and optionally cached on the server.
    • Footprint: Zero JavaScript footprint on the client.
    • Lazy Loading: Uses native browser loading="lazy".
    • Placeholder: Uses the background of the image itself. Warning: Do not use this for images with alpha channels (transparency), as the placeholder is not removed when the image loads.
    • Output: Generates a single <picture /> element.

    <Image /> (Client Component)

    • Rendering: Runs in the browser.
    • Footprint: Includes a JavaScript footprint.
    • Lazy Loading: Uses IntersectionObserver, allowing for customizable loading thresholds.
    • Placeholder: Supports a smooth cross-fade effect between the placeholder and the original image.
    • Output: Generates more complex HTML with multiple elements around the <picture /> element.
    import { Image, RSCImage } from 'react-datocms';
    
    // Server Component usage
    <RSCImage data={responsiveImageData} />
    
    // Client Component usage
    <Image data={responsiveImageData} />
  6. How group and boundary resolution works for Visual Editing

    master

    The ContentLink component uses DOM traversal to determine which element becomes the clickable target for Visual Editing when it encounters stega-encoded content. When an element containing stega data is clicked, the library walks up the DOM tree following these rules:

    1. Group (data-datocms-content-link-group): If a group is found, the library stops and makes that group element the clickable target.
    2. Boundary (data-datocms-content-link-boundary): If a boundary is found, the library stops and makes the starting element (the one containing the stega data) the clickable target, preventing further traversal.
    3. Root: If neither is found, the starting element itself becomes the target.

    Collision Warning

    If multiple stega-encoded strings exist within the same parent element without being wrapped in their own elements, they will all resolve to the same target. The library will log a console warning and the last URL will win. To avoid this, wrap each piece of content in its own element (e.g., a <span>).

    <!-- Example of nested groups: inner group wins for its content -->
    <div data-datocms-content-link-group>
      <h1>{page.title}</h1> {/* Resolves to outer div if title is stega-encoded */}
      <div data-datocms-content-link-group>
        <p>{page.subtitle}</p> {/* Resolves to inner div if subtitle is stega-encoded */}
      </div>
    </div>
    
    <!-- Example of boundary: prevents bubbling to parent group -->
    <div data-datocms-content-link-group>
      <h1>{page.title}</h1>
      <section data-datocms-content-link-boundary>
        <span>{page.author}</span> {/* Resolves to the span itself due to boundary */}
      </section>
    </div>
  7. Configure Structured Text fields for Visual Editing

    master

    Structured Text fields require specific patterns to ensure both the main field and its embedded components (blocks/records) are clickable and point to the correct editor URLs.

    Rule 1: Wrap the component in a group

    Because stega encoding is often contained within a tiny <span> inside the text, you must wrap the entire StructuredText component in a data-datocms-content-link-group to make the whole area clickable.

    Rule 2: Use boundaries for embedded content

    Embedded blocks, inline records, and inline blocks have their own unique editing URLs. To prevent clicking them from triggering the parent Structured Text editor, wrap them in a data-datocms-content-link-boundary.

    Note: renderLinkToRecord does not require a boundary because record links typically don't introduce a new editing target that would collide with the parent group.

    <div data-datocms-content-link-group>
      <StructuredText
        data={page.content}
        renderBlock={({ record }) => (
          <div data-datocms-content-link-boundary>
            <BlockComponent block={record} />
          </div>
        )}
        renderInlineRecord={({ record }) => (
          <span data-datocms-content-link-boundary>
            <InlineRecordComponent record={record} />
          </span>
        )}
        renderInlineBlock={({ record }) => (
          <span data-datocms-content-link-boundary>
            <InlineBlockComponent record={record} />
          </span>
        )}
      />
    </div>
  8. Integrate ContentLink with React Router

    master

    To enable full Web Previews plugin integration in React Router, provide navigation callbacks using useNavigate and useLocation from react-router-dom.

    import { ContentLink as DatoContentLink } from 'react-datocms';
    import { useNavigate, useLocation } from 'react-router-dom';
    
    export function ContentLink() {
      const navigate = useNavigate();
      const location = useLocation();
    
      return (
        <DatoContentLink
          onNavigateTo={(path) => navigate(path)}
          currentPath={location.pathname}
        />
      );
    }
  9. Develop and build the datocms-react-examples app

    master

    Use these commands to manage the development and production lifecycle of the example project:

    • Development: Run npm start to start the app in development mode. The app will be available at http://localhost:3000 and will automatically reload when you make changes.
    • Production Build: Run npm run build to create a production-ready build folder. This command bundles React in production mode, optimizes the build for performance, minifies files, and includes hashes in filenames for caching.
    • Ejecting: Run npm run eject if you need full control over the underlying build tools (webpack, Babel, ESLint, etc.). Warning: This is a one-way operation and cannot be undone.
    npm start
    npm run build
    npm run eject
  10. Use responsive images with `<Image />` or `<RSCImage />`

    master

    To implement responsive images, follow these two steps:

    1. Query Data: Use the responsiveImage GraphQL query in your DatoCMS project. This returns optimized thumbnails and metadata.
    2. Render Component: Import Image or RSCImage from react-datocms and pass the responsiveImage object to the data prop.

    To get the best performance, use imgixParams: { auto: format }. This allows the browser to request the most efficient format (like AVIF or WebP) without increasing your GraphQL response size.

    import React from 'react';
    import { Image, RSCImage } from 'react-datocms';
    
    const Page = ({ data }) => (
      <div>
        {/* Uses native loading="lazy" */}
        <RSCImage data={data.blogPost.cover.responsiveImage} />
        
        {/* Uses custom lazy-loading via IntersectionObserver */}
        <Image data={data.blogPost.cover.responsiveImage} />
      </div>
    );
    
    const query = gql`
      query {
        blogPost {
          cover {
            responsiveImage(imgixParams: { fit: crop, w: 300, h: 300, auto: format }) {
              src
              srcSet
              width
              height
              alt
              title
              base64
              bgColor
              sizes
            }
          }
        }
      }
    `;
    import React from 'react';
    import { Image, RSCImage } from 'react-datocms';
    
    const Page = ({ data }) => (
      <div>
        <RSCImage data={data.blogPost.cover.responsiveImage} />
        <Image data={data.blogPost.cover.responsiveImage} />
      </div>
    );