diff --git a/.changeset/fix-slots-infinite-render.md b/.changeset/fix-slots-infinite-render.md new file mode 100644 index 00000000000..1227156515c --- /dev/null +++ b/.changeset/fix-slots-infinite-render.md @@ -0,0 +1,5 @@ +--- +"@primer/react": patch +--- + +Fix slots infinite rendering when no `context` prop is provided diff --git a/src/__tests__/utils/createSlots.test.tsx b/src/__tests__/utils/createSlots.test.tsx index 980572508db..92cde9b4f30 100644 --- a/src/__tests__/utils/createSlots.test.tsx +++ b/src/__tests__/utils/createSlots.test.tsx @@ -5,11 +5,11 @@ import createSlots from '../../utils/create-slots' // setup a component with slots const {Slots, Slot} = createSlots(['One', 'Two', 'Three']) -type ContextTypes = {salutation?: string} +type Props = {context?: {salutation: string}} -const ComponentWithSlots: React.FC> = ({salutation, children}) => { +const ComponentWithSlots: React.FC> = ({context, children}) => { return ( - + {slots => (
{slots.One} @@ -25,9 +25,9 @@ const SlotItem1: React.FC> = ({children}) => > = ({children}) => {children} const SlotItem3: React.FC> = ({children}) => ( - {(context: ContextTypes) => ( + {(context: Props['context']) => ( <> - {context.salutation} {children} + {context?.salutation} {children} )} @@ -64,7 +64,7 @@ describe('ComponentWithSlots', () => { it('renders with context passed to children', async () => { const component = render( - + third free form diff --git a/src/utils/create-slots.tsx b/src/utils/create-slots.tsx index 2a1b51eec7c..de1c73ca31a 100644 --- a/src/utils/create-slots.tsx +++ b/src/utils/create-slots.tsx @@ -23,6 +23,9 @@ const createSlots = (slotNames: SlotNames[]) => { context: {} }) + // maintain a static reference to avoid infinite render loop + const defaultContext = Object.freeze({}) + /** Slots uses a Double render strategy inspired by [reach-ui/descendants](https://github.com/reach/reach-ui/tree/develop/packages/descendants) * Slot registers themself with the Slots parent. * When all the children have mounted = registered themselves in slot, @@ -33,7 +36,7 @@ const createSlots = (slotNames: SlotNames[]) => { context?: ContextProps['context'] children: (slots: Slots) => React.ReactNode }> - > = ({context = {}, children}) => { + > = ({context = defaultContext, children}) => { // initialise slots const slotsDefinition: Slots = {} slotNames.map(name => (slotsDefinition[name] = null))