Real-time updates
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 Router project, it's extremely easy to use our Real-time Updates API to perform such changes, as it only involves adding a React hook to your page components.
How to use the useQuerySubscription hook
The react-datocms package exposes a useQuerySubscription hook that makes it trivial to update any React Router page in real-time.
The hook works by streaming any changes present to the response of a GraphQL query directly to the browser, and it a loader responsibility to prepare an object compatible with the options of the hook itself.
The following code shows a complete example that activates real-time updates for any visitor of your website:
import type { Route } from './+types/blog-post';import { useQuerySubscription } from 'react-datocms';import { load } from '~/lib/datocms';
const BLOG_POST_QUERY = `query HomePage { blogPost { title }}`;
export async function loader() { return { subscription: { query: BLOG_POST_QUERY, initialData: await load(BLOG_POST_QUERY), token: process.env.DATOCMS_READONLY_TOKEN, environment: process.env.DATOCMS_ENVIRONMENT, }, };}
export default function BlogPost({ loaderData }: Route.ComponentProps) { const { data, error, status } = useQuerySubscription(loaderData.subscription);
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 && ( <div>{JSON.stringify(data, null, 2)}</div> )} </div> );} Preview Mode + useQuerySubscription
Another common scenario is being able to activate real-time updates of draft content only for content editors that are signed-in to the website via Preview Mode:
In this case, you don't want to expose your API token or pass down additional arguments to regular users, so:
Make sure to pass the
includeDrafts: trueoption only if Preview Mode is active (that is, if thepreviewkey is set on the session), so that only content editors will see draft content;If Preview Mode is off, fill in the
subscriptionobject returned by the loader with justinitialDataandenabled: falseoptions, without any additional clutter.
Here's an example snippet:
import type { Route } from './+types/blog-post';import { load } from '~/lib/datocms';import { getSession } from '~/sessions';
const BLOG_POST_QUERY = `query HomePage { blogPost { title }}`;
export async function loader({ request }: Route.LoaderArgs) { const session = await getSession(request.headers.get('Cookie')); const previewModeActive = session.has('preview');
const initialData = await load(BLOG_POST_QUERY, { includeDrafts: previewModeActive, });
return { subscription: previewModeActive ? { query: BLOG_POST_QUERY, initialData, token: process.env.DATOCMS_READONLY_TOKEN, environment: process.env.DATOCMS_ENVIRONMENT, includeDrafts: true, } : { enabled: false, initialData, }, };}