> Portal Navigation:
> 
> - Append `.md` to any URL under `https://dev.wix.com/docs/` to get its markdown version.
> - Pages are either content pages (article or reference text) or menu pages (a list of links to child pages).
> - To get a menu page, truncate any URL to a parent path and append `.md` (e.g. `https://dev.wix.com/docs/sdk.md`, `https://dev.wix.com/docs/sdk/core-modules.md`).
> - Top-level index of all portals: https://dev.wix.com/docs/llms.txt
> - Full concatenated docs: https://dev.wix.com/docs/llms-full.txt

## Resource: Sync a Custom Panel with External Data

## Article: Sync a Custom Panel with External Data

## Article Link: https://dev.wix.com/docs/build-apps/develop-your-app/extensions/site-extensions/editor-react-components/custom-panels/sync-a-custom-panel-with-external-data.md

## Article Content:

# Sync a Custom Panel with External Data

<blockquote class="caution">

__Alpha:__
Editor React Components are currently in alpha. This feature is subject to change and may have bugs, issues, and limitations. We're actively improving it based on your feedback.

</blockquote>

[`setData()`](https://dev.wix.com/docs/sdk/host-modules/editor/react-elements/data/set-data.md) and [`getData()`](https://dev.wix.com/docs/sdk/host-modules/editor/react-elements/data/get-data.md) read and write the `data` fields declared in your component's manifest. Many custom panels manage content that lives somewhere else instead, such as a Wix Data collection or content fetched from your app's backend. In that case, the editor canvas has no way to know your content changed, because nothing in the manifest changed.

This article shows how to bridge that gap: pushing a snapshot of your external content into a manifest field your component already watches, and avoiding the read-after-write timing issue that comes with combining a pushed snapshot with a live data fetch.

## Before you begin

Make sure you have the following set up:

- A [custom panel](https://dev.wix.com/docs/build-apps/develop-your-app/extensions/site-extensions/editor-react-components/custom-panels/build-a-custom-panel.md) for your Editor React Component
- A data source outside the manifest that your panel manages, such as a [Wix Data](https://dev.wix.com/docs/api-reference/business-solutions/cms/operations/introduction.md) collection

## The problem

Your custom panel and your component run in separate contexts, and the only channel between them is the manifest's `data` and style values. There's no separate call for telling the canvas to refresh: the editor re-renders your component when a bound value actually changes, and not otherwise.

Take a testimonial carousel that shows quotes from a Wix Data collection instead of a single manifest-declared `quote` field. A Wix user picks which quotes appear and reorders them from your custom panel. The panel writes those changes directly to the collection with the Wix Data SDK, not through `setData()`, since the content isn't part of the manifest. Nothing bound changed, so the canvas has no way to know your content changed.

Your component still needs to query that collection itself to render the carousel. If it only queries once, on mount, it won't reflect changes the Wix user makes in the panel afterward. If you have it re-query after every panel action, you introduce a race: Wix Data replicates writes to several mirror instances, and a query issued immediately after a write can still return a mirror's pre-write data before that replication catches up. See [Wix Data and Eventual Consistency](https://dev.wix.com/docs/api-reference/business-solutions/cms/eventual-consistency.md).

## Step 1 | Add a revision field to the manifest

Add a `data` field to your manifest that exists only to signal that your external content changed. It doesn't drive any UI in the component:

```typescript
data: {
  contentRevision: {
    dataType: 'text',
    displayName: 'Content Revision',
  },
},
```

## Step 2 | Push a snapshot from your panel

Whenever your panel writes a change to your external content, also serialize the current state into `contentRevision` with [`setData()`](https://dev.wix.com/docs/sdk/host-modules/editor/react-elements/data/set-data.md). Always include something guaranteed to change, such as a timestamp: the editor only re-renders when a bound value changes, so writing the exact same string twice in a row does nothing the second time.

```tsx
import { reactElements } from '@wix/editor';

async function publishQuoteOrder(setId: string, quotes: Quote[]) {
  await updateQuoteOrderInCollection(setId, quotes); // Your own Wix Data write.

  await reactElements.setData({
    contentRevision: JSON.stringify({ t: Date.now(), quotes }),
  });
}
```

Pass the current `quotes` value into this function instead of reading it back from the component first with `getData()`. If your panel already has the value it's about to write, an extra read before the write is redundant.

Because `contentRevision` is a manifest field, updating it triggers the same prop update your component already receives for any other `data` field. No extra wiring is required.

## Step 3 | Read the snapshot in your component

In your component, parse `contentRevision` and use it as the initial source for what to render, instead of waiting on your own query to resolve:

```tsx
function parseSnapshot(revision?: string): Quote[] | null {
  if (!revision) return null;
  try {
    return JSON.parse(revision).quotes ?? null;
  } catch {
    return null;
  }
}

function TestimonialCarousel({ contentRevision }: TestimonialCarouselProps) {
  const snapshot = parseSnapshot(contentRevision);
  const [quotes, setQuotes] = useState<Quote[]>(snapshot ?? []);

  useEffect(() => {
    const next = parseSnapshot(contentRevision);
    if (next) setQuotes(next);
  }, [contentRevision]);

  // ...
}
```

The component now updates the moment the panel pushes a snapshot, without a round trip to your data source.

## Step 4 | Read with `consistentRead`

Your component likely still needs its own query, for example to load quotes the first time the panel hasn't touched `contentRevision` yet, or to keep the live site in sync without a panel present.

Wix Data replicates every write to several mirror database instances, and a normal read hits the nearest mirror to save time. A query issued right after your panel's write can still return that mirror's pre-write data, because it hasn't caught up yet. Pass `consistentRead: true` to the read so it queries the primary instance directly instead. For more information, see [Wix Data and Eventual Consistency](https://dev.wix.com/docs/api-reference/business-solutions/cms/eventual-consistency.md).

```tsx
useEffect(() => {
  let active = true;

  queryQuotesFromCollection(setId, { consistentRead: true }).then((fetched) => {
    if (!active) return;
    setQuotes(fetched);
  });

  return () => {
    active = false;
  };
}, [setId]);
```

`consistentRead` costs some latency on that query. It's worth it here, since it's what guarantees your component doesn't overwrite the panel's snapshot with data read from a mirror that hasn't caught up yet.

The snapshot only exists to make the canvas refresh immediately, without waiting on this query. Your data source is still the source of truth: keep querying it.

## Keep your panel in sync with external edits

If a value can also change outside your panel, for example a field an auto panel exposes alongside a related field your custom panel manages, subscribe to it with [`onChange()`](https://dev.wix.com/docs/sdk/host-modules/editor/react-elements/change-events/on-change.md) so your panel's own UI reflects edits made elsewhere:

```tsx
useEffect(() => {
  let unsubscribe: (() => void) | undefined;

  reactElements.onChange((patch) => {
    if (patch.type === 'data') {
      // Refresh your panel's local state from the updated data.
    }
  }).then((unsub) => {
    unsubscribe = unsub;
  });

  return () => unsubscribe?.();
}, []);
```

## See also

- [Build a Custom Panel](https://dev.wix.com/docs/build-apps/develop-your-app/extensions/site-extensions/editor-react-components/custom-panels/build-a-custom-panel.md)
- [About Custom Panels for Editor React Components](https://dev.wix.com/docs/build-apps/develop-your-app/extensions/site-extensions/editor-react-components/custom-panels/about-custom-panels.md)
- [setData()](https://dev.wix.com/docs/sdk/host-modules/editor/react-elements/data/set-data.md)
- [onChange()](https://dev.wix.com/docs/sdk/host-modules/editor/react-elements/change-events/on-change.md)
- [Wix Data Introduction](https://dev.wix.com/docs/api-reference/business-solutions/cms/operations/introduction.md)
- [Wix Data and Eventual Consistency](https://dev.wix.com/docs/api-reference/business-solutions/cms/eventual-consistency.md)