Slot fields defined within object and array fields remount on component changes
Description
The current implementation of useFieldTransformsTracked re-calls field transforms when the field values changes shallowly. This is fine most of the times, but this means that if a slot is defined at a nested object or array, it will be recreated whenever any of the fields within that array or slot change.
There's a workaround, though. If you call the slot as a function instead of as a component, then it won't remount because React will only see its return component references which should be stable across re-renders:
// This REMOUNTS
render: ({ myObject: { title, mySlot: MySlot } }) => {
return <div><MySlot /></div>
}
// This DOESN'T
render: ({ myObject }) => {
return <div>{myObject.mySlot()}</div>
} Environment
- Puck version: 0.22.4
Steps to reproduce
- Render Puck with a slot nested within an object or array field that has some other field; and a component that logs on remounts
const Editor = () => {
return (
<div style={{ display: "grid" }}>
<Puck config={config} data={data} />
</div>
);
};- Navigate to the editor
- Add the slot component
- Add a component within the slot
- Modify the object field
What happens
The nested components remount because the slots change reference.
What I expect to happen
For the nested components to not remount
Notes for fixing
We could accept the flatten node within useFieldTransformsTracked, instead of the expanded node. That would only check primitive values. In both places we call the hook we actually expand the props before passing them down, so we already have those props in.
Source: puckeditor/puck