Last active
December 23, 2021 16:21
-
-
Save brombal/64c8a19b8f0b673d373f4defa136db20 to your computer and use it in GitHub Desktop.
RenderOne - a React component that only renders one truthy child (like a switch/case for JSX)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
<RenderOne> renders only its first <Case> child whose `when` prop is truthy. If no <Case> has a truthy `when` prop, | |
the first <Case> with no `when` prop present will render. | |
E.g.: | |
```jsx | |
<RenderOne> | |
<Case when={someCondition}> | |
... someCondition is true ... | |
</Case> | |
<Case when={someOtherCondition}> | |
... someOtherCondition is true ... | |
</Case> | |
<Case> | |
... nothing is true ... | |
</Case> | |
</RenderOne> | |
``` | |
<Case> elements can contain children (as above), or a `render` prop that returns a React node: | |
```jsx | |
<RenderOne> | |
<Case | |
when={someObject} | |
render={() => ( | |
<>... {someObject.property} ...</> | |
)} | |
/> | |
</RenderOne> | |
``` | |
Keep in mind that a <Case> element's children will still be evaluated (but not rendered) even | |
if its `when` prop is false, so variables may be undefined or other side effects may occur. | |
Use the `render` prop for these scenarios, which isn't called unless the <Case> element's `when` | |
prop is true. | |
*/ | |
import * as React from 'react'; | |
interface RenderOneProps { | |
children: React.ReactElement<typeof Case>[]; | |
} | |
export function RenderOne(props: RenderOneProps) { | |
return ( | |
<> | |
{React.Children.toArray(props.children).find( | |
(c: any) => !!c.props.when || !('when' in c.props), | |
)} | |
</> | |
); | |
} | |
interface CaseRenderProps { | |
when?: any; | |
render(): React.ReactNode; | |
} | |
interface CaseChildrenProps { | |
when?: any; | |
children: any; | |
} | |
export function Case(props: CaseRenderProps | CaseChildrenProps) { | |
const anyProps = props as any; | |
return anyProps.children || anyProps.render(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment