Automatic content reload
Learn how automatic content reload works and how you can customize it.
# Overview
Whenever a content editor makes a change - e.g. edit a field or add a component, everyone who's currently working on the same Visual Editor project should immediately see this change.
This is a core benefit of Visual Editor: everything you or your project collaborators do is visually reflected to all editors, instead of having to go through a lengthy server restart or publishing process just to preview changes.
Normally, sites running in production don't have this functionality: pages are either statically-generated as possible or otherwise heavily cached, and generally do not update on any content change after they've already been rendered in a user's browser.
To provide instant content updates in our Visual Editor, a few things need to happen:
- The web server should run in a mode that doesn't apply pre-generation or caching to pages. This is commonly known as development mode in most web frameworks.
- Content changes should be detected via some watching mechanism.
- When a change is detected, clients should be notified and refresh the page content without reloading the whole page, with minimal interruption to the end-user.
This typically requires framework-specific code, e.g. for Next.js, using therouter
object to re-navigate to the current page.
This process is exactly the same for both the editor who just made the change and for any other users working concurrently. There is no separate code path for refreshing the page based on whether you've made the change or anyone else.
# Automatic content reload
Starting in version 0.5.0, here's how it works:
- When running locally, the
stackbit dev
process watches for changes in the content source configured for your site. When we run your site ourselves for content editors (which we do for every Visual Editor project), our runtime environment does the same. - When a change is detected, all open Visual Editors get notified.
- At this point, your code can be notified and take control of what happens next - if you wish. We'll get to that in a second.
- Unless you've explicitly handled the change event in your codebase, Visual Editor will proceed to refresh the page by itself. The actual mechanism depends on the framework used (e.g. using the
router
object for Next.js, as mentioned above).
Hence, by default, everything just works - with no extra code required on your site.
# Capture & handle change events
In automatic mode, Visual Editor always detects content changes by itself. However, there are scenarios in which you may opt to handle the actual page refresh yourself:
- When there is a method to efficiently refresh the page that's specific to your site (e.g. calling an API endpoint you control that will bring in updated content for the page in the fastest manner). Check back soon for examples.
- When you want to bring in a web framework we don't yet have built-in support for and use its fast refresh path to update the page.
- If you want to control whether a displayed page will refresh at all, given which content objects have been changed.
By default, a page refresh will always occur regardless of what content has changed, since any page may render multiple content objects (that are referenced by each other, etc.). However, we provide detailed data on what content has changed that you can use to make the call yourself. Seeevent.detail
below.
# Add an event listener
To receive change events in your client-side code, add a window-level event listener for the stackbitObjectsChanged
event:
window.addEventListener("stackbitObjectsChanged", event => {
// Override default refresh behavior ...
});
See the event reference for more details on the event object.
# Next.js example
The event listener will run on all pages by using the App component.
// src/pages/_app.js
import * as React from "react";
const CHANGE_EVENT = "stackbitObjectsChanged";
export default function MyApp({ Component, pageProps }) {
const onContentChange = e => {
// Override the default refresh behavior just for a specific URL
if (e.detail.currentUrl === "/about") {
e.preventDefault();
/* myRefreshCodeJustForAbout() ... */
}
};
/*
When any page is mounted, add the listener.
Note the function returned by the callback, which will be called on unmount,
and the empty dependency array to prevent this from running on any re-render.
*/
React.useEffect(() => {
window.addEventListener(CHANGE_EVENT, onContentChange);
return () => {
window.removeEventListener(CHANGE_EVENT, onContentChange);
};
}, []);
return <Component {...pageProps} />;
}
# Conditional refresh
You can override Visual Editor’s default behavior just in certain conditions or for specific URLs, by conditionally calling e.preventDefault()
just when appropriate.
For example, if you're methodically annotating all content objects used to render a given page with data-sb-object-id data attributes, you can prevent a refresh when there's no intersection between changed objects and on-page objects:
const onContentChange = e => {
const intersects = e.detail.changedObjectIds.some(o =>
e.detail.visibleObjectIds.includes(o)
);
if (!intersects) e.preventDefault();
};
# Custom content reload
To handle content change detection & refresh fully within your codebase, add the following to your configuration file:
export default {
stackbitVersion: "~0.6.0",
customContentReload: true
};
With customContentReload set to true
Visual Editor will not notify you of content changes, nor will it refresh the page.
# When to go fully custom
- If you're using Sourcebit as many existing projects do.
This package is optional and external to Visual Editor itself. It handles change detection & page refresh by itself for supported content sources & web frameworks. - If your application implements a cache layer on top of your content source, you need to ensure that this cache is up-to-date with content changes before the page is being refreshed. This requires having your own pipeline for content change detection => cache update/invalidation => page refresh. You can find an example of that in the sourcebit-target-next plugin.
Did you find this doc useful?
Your feedback helps us improve our docs.