puck
puck copied to clipboard
Eliminate re-rendering of components when hovered in the canvas
Closes #1442
Description
This PR fixes a performance issue where components re-rendered when hovered over in the canvas.
Changes made
- The
renderPreviewfunction inDropZoneChildwas moved to its own component to simplify the code and avoid remounting and unnecessary re-renders. - The
DropZoneChildcomponent now usesMemoizeComponentto render user components. This component accepts two props: the component to render, and the props to pass to it. It memoizes the rendering by only re-rendering when the props change, using shallow comparison for general props and deep comparison for thepuckprop. This approach was chosen because user props can be large and deeply nested, making deep equality checks costly. For solving the hover-related re-renders, this level of optimization was enough. - A new
shallowEqualutility was introduced to check for shallow equality between two objects.
How to test
- Render the Puck editor with a config that uses slots:
const config = {
components: {
Slot: {
fields: { items: { type: "slot" } },
render: ({ items: Items }) => {
console.log("Re-rendering Slot");
return <Items />;
}
},
Heading: {
fields: { title: { type: "text" } },
defaultProps: { title: "Heading" },
render: ({ title }) => {
console.log("Re-rendering Heading");
return <h1>{title}</h1>;
}
}
}
};
- Navigate to the editor.
- Open the devtools console.
- Drag and drop a
Slot. - Drag and drop two
Headingcomponents inside theSlot. - Hover over the
Slotcomponent. - Watch the console.
- Confirm that no re-rendering logs are printed.
https://github.com/user-attachments/assets/72099349-fc6f-4831-9a3c-fbe318dea87f