Dynamic Props
Dynamic prop resolution allows you to change the props for a component after the props have been changed by the user. This is useful for making third-party API calls, such as requesting the latest content from a headless CMS.
Dynamic component props
The resolveData
function allows you to make changes to the props and set fields as read-only.
For example, we can set the value of one prop to another:
const config = {
components: {
HeadingBlock: {
fields: {
title: {
type: "text",
},
resolvedTitle: {
type: "text",
},
},
resolveData: async ({ props }) => {
return {
props: {
resolvedTitle: props.title,
},
};
},
render: ({ resolvedTitle }) => {
return <h1>{resolvedTitle}</h1>;
},
},
},
};
Setting fields as read-only
resolveData
also allows us to mark fields as read-only using the readOnly
parameter.
const config = {
components: {
HeadingBlock: {
// ...
resolveData: async ({ props }) => {
return {
props: {
resolvedTitle: props.title,
},
readOnly: { resolvedTitle: true },
};
},
// ...
},
},
};
Preventing duplicate calls
It's possible that resolveData
may carry out an expensive operation (like an API call) that we want to avoid making unless a specific prop has changed.
This can be restricted by checking the changed
param before calling any expensive operations.
const config = {
components: {
HeadingBlock: {
// ...
resolveData: async ({ props }, { changed }) => {
if (!changed.text) return { props };
return {
props: {
resolvedTitle: await expensiveOperation(props.title),
},
};
},
// ...
},
},
};
Dynamic Root props
The resolveData
method is also available on the root component.
const config = {
components: {},
root: {
fields: {
title: {
type: "text",
},
resolvedTitle: {
type: "text",
},
},
resolveData: async ({ props }) => {
return {
props: {
resolvedTitle: props.title,
},
};
},
render: ({ children, resolvedTitle }) => {
return (
<>
<h1>{resolvedTitle}</h1>
{children}
</>
);
},
},
};
Triggering resolveData
Resolve data is triggered whenever the props for a component change, or when the resolveAllData
utility is used.
import { resolveAllData } from "@measured/puck";
const updatedData = await resolveAllData(data, config);