Skip to content

Commit

Permalink
Fix slots infinite rendering when no context prop is provided (#2219)
Browse files Browse the repository at this point in the history
* Add basic tests for `createSlots`

* Fix infinite slot rendering when context prop not provided

* Create changelog

* Update to use existing tests
  • Loading branch information
iansan5653 committed Aug 11, 2022
1 parent 47725a9 commit af534f1
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .changeset/fix-slots-infinite-render.md
@@ -0,0 +1,5 @@
---
"@primer/react": patch
---

Fix slots infinite rendering when no `context` prop is provided
12 changes: 6 additions & 6 deletions src/__tests__/utils/createSlots.test.tsx
Expand Up @@ -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<React.PropsWithChildren<ContextTypes>> = ({salutation, children}) => {
const ComponentWithSlots: React.FC<React.PropsWithChildren<Props>> = ({context, children}) => {
return (
<Slots context={{salutation}}>
<Slots context={context}>
{slots => (
<div>
{slots.One}
Expand All @@ -25,9 +25,9 @@ const SlotItem1: React.FC<React.PropsWithChildren<unknown>> = ({children}) => <S
const SlotItem2: React.FC<React.PropsWithChildren<unknown>> = ({children}) => <Slot name="Two">{children}</Slot>
const SlotItem3: React.FC<React.PropsWithChildren<unknown>> = ({children}) => (
<Slot name="Three">
{(context: ContextTypes) => (
{(context: Props['context']) => (
<>
{context.salutation} {children}
{context?.salutation} {children}
</>
)}
</Slot>
Expand Down Expand Up @@ -64,7 +64,7 @@ describe('ComponentWithSlots', () => {

it('renders with context passed to children', async () => {
const component = render(
<ComponentWithSlots salutation="hi">
<ComponentWithSlots context={{salutation: 'hi'}}>
<SlotItem3>third</SlotItem3>
free form
</ComponentWithSlots>
Expand Down
5 changes: 4 additions & 1 deletion src/utils/create-slots.tsx
Expand Up @@ -23,6 +23,9 @@ const createSlots = <SlotNames extends string>(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,
Expand All @@ -33,7 +36,7 @@ const createSlots = <SlotNames extends string>(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))
Expand Down

0 comments on commit af534f1

Please sign in to comment.