From 15c7f0dbf3ebf5c6a2bb011970dda515a15acb56 Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Thu, 12 Oct 2023 14:20:02 -0400 Subject: [PATCH] docs: updates building your own live preview hook (#3604) --- docs/live-preview/frontend.mdx | 38 +++++++++++++++++++++++++++------- docs/live-preview/overview.mdx | 2 +- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/docs/live-preview/frontend.mdx b/docs/live-preview/frontend.mdx index 727d4e26cd..5aa7ffa67a 100644 --- a/docs/live-preview/frontend.mdx +++ b/docs/live-preview/frontend.mdx @@ -88,13 +88,14 @@ This package provides the following functions: | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **`subscribe`** | Subscribes to the Admin panel's `window.postMessage` events and calls the provided callback function. | | **`unsubscribe`** | Unsubscribes from the Admin panel's `window.postMessage` events. | +| **`ready`** | Sends a `window.postMessage` event to the Admin panel to indicate that the front-end is ready to receive messages. | The `subscribe` function takes the following args: | Path | Description | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **`callback`** \* | A callback function that is called with `data` every time a change is made to the document. | -| **`serverURL`** \* | The URL of your Payload server. git s | +| **`serverURL`** \* | The URL of your Payload server. | | **`initialData`** | The initial data of the document. The live data will be merged in as changes are made. | | **`depth`** | The depth of the relationships to fetch. Defaults to `0`. | @@ -103,18 +104,23 @@ With these functions, you can build your own hook using your front-end framework ```tsx import { subscribe, unsubscribe } from '@payloadcms/live-preview'; -// Build your own hook to subscribe to the live preview events -// This function will handle everything for you like -// 1. subscribing to `window.postMessage` events -// 2. merging initial page data with incoming form state -// 3. populating relationships and uploads +// To build your own hook, subscribe to Live Preview events using the`subscribe` function +// It handles everything from: +// 1. Listening to `window.postMessage` events +// 2. Merging initial data with active form state +// 3. Populating relationships and uploads +// 4. Calling the `onChange` callback with the result +// Your hook should also: +// 1. Tell the Admin panel when it is ready to receive messages +// 2. Handle the results of the `onChange` callback to update the UI +// 3. Unsubscribe from the `window.postMessage` events when it unmounts ``` Here is an example of what the same `useLivePreview` React hook from above looks like under the hood: ```tsx -import { subscribe, unsubscribe } from '@payloadcms/live-preview' -import { useCallback, useEffect, useState } from 'react' +import { subscribe, unsubscribe, ready } from '@payloadcms/live-preview' +import { useCallback, useEffect, useState, useRef } from 'react' export const useLivePreview = (props: { depth?: number @@ -127,13 +133,18 @@ export const useLivePreview = (props: { const { depth = 0, initialData, serverURL } = props const [data, setData] = useState(initialData) const [isLoading, setIsLoading] = useState(true) + const hasSentReadyMessage = useRef(false) const onChange = useCallback((mergedData) => { + // When a change is made, the `onChange` callback will be called with the merged data + // Set this merged data into state so that React will re-render the UI setData(mergedData) setIsLoading(false) }, []) useEffect(() => { + // Listen for `window.postMessage` events from the Admin panel + // When a change is made, the `onChange` callback will be called with the merged data const subscription = subscribe({ callback: onChange, depth, @@ -141,6 +152,17 @@ export const useLivePreview = (props: { serverURL, }) + // Once subscribed, send a `ready` message back up to the Admin panel + // This will indicate that the front-end is ready to receive messages + if (!hasSentReadyMessage.current) { + hasSentReadyMessage.current = true + + ready({ + serverURL + }) + } + + // When the component unmounts, unsubscribe from the `window.postMessage` events return () => { unsubscribe(subscription) } diff --git a/docs/live-preview/overview.mdx b/docs/live-preview/overview.mdx index c0006226eb..a33b330b2c 100644 --- a/docs/live-preview/overview.mdx +++ b/docs/live-preview/overview.mdx @@ -85,7 +85,7 @@ Here is an example of using a function that returns a dynamic URL: locale }) => `${data.tenant.url}${ // Multi-tenant top-level domain documentInfo.slug === 'posts' ? `/posts/${data.slug}` : `${data.slug !== 'home' : `/${data.slug}` : ''}` - `}?locale=${locale}`, // Localization query param + }${locale ? `?locale=${locale?.code}` : ''}`, // Localization query param collections: ['pages'], }, }