diff --git a/packages/@react-facet/core/src/components/With.spec.tsx b/packages/@react-facet/core/src/components/With.spec.tsx index d1a2e07e..95c91817 100644 --- a/packages/@react-facet/core/src/components/With.spec.tsx +++ b/packages/@react-facet/core/src/components/With.spec.tsx @@ -1,9 +1,9 @@ import React from 'react' -import { render } from '@react-facet/dom-fiber-testing-library' +import { act, render } from '@react-facet/dom-fiber-testing-library' import { With } from '.' import { createFacet } from '../facet' import { Facet, NO_VALUE } from '../types' -import { useFacetMap } from '../hooks' +import { useFacetEffect, useFacetMap } from '../hooks' it('renders when not null, passing down the information', () => { const userFacet = createFacet({ initialValue: { user: 'Zelda' } }) @@ -65,3 +65,34 @@ it('does not render facet has no value', () => { expect(rendered).not.toHaveBeenCalled() }) + +it('correctly handles unmounting', () => { + const mockFacet = createFacet({ initialValue: 'abc' }) + + const Content = ({ data }: { data: Facet }) => { + useFacetEffect( + (data) => { + if (data === null || data === undefined) { + throw new Error('data should not be null') + } + }, + [], + [data], + ) + + return <>mounted + } + + const Example = () => { + return {(mock) => } + } + const scenario = + + const result = render(scenario) + + expect(result.container).toHaveTextContent('mounted') + + act(() => mockFacet.set(null)) + + expect(result.container).not.toHaveTextContent('mounted') +}) diff --git a/packages/@react-facet/core/src/components/With.tsx b/packages/@react-facet/core/src/components/With.tsx index 183ed3c8..cc79e4c7 100644 --- a/packages/@react-facet/core/src/components/With.tsx +++ b/packages/@react-facet/core/src/components/With.tsx @@ -1,19 +1,23 @@ import { ReactElement } from 'react' +import { useFacetMemo } from '../hooks/useFacetMemo' import { useFacetUnwrap } from '../hooks/useFacetUnwrap' import { useFacetMap } from '../hooks/useFacetMap' -import { Facet, NoValue } from '../types' +import { Facet, NO_VALUE } from '../types' type WithProps = { data: Facet children: (data: Facet) => ReactElement | null } -const hasData = (_: Facet, shouldRender: boolean | NoValue): _ is Facet => { - return shouldRender === true -} - +/** + * Conditionally renders a child if a given facet value is not null or undefined + * + * @param data facet value which can be null or undefined + * @param children render prop which receives the transformed facet + */ export const With = ({ data, children }: WithProps) => { const shouldRenderFacet = useFacetMap((data) => data !== null && data !== undefined, [], [data]) const shouldRender = useFacetUnwrap(shouldRenderFacet) - return hasData(data, shouldRender) ? children(data) : null + const nonNullData = useFacetMemo((data) => (data !== null && data !== undefined ? data : NO_VALUE), [], [data]) + return shouldRender === true ? children(nonNullData) : null }