Skip to content

Instantly share code, notes, and snippets.

@brombal
Last active December 23, 2021 16:21
Show Gist options
  • Save brombal/64c8a19b8f0b673d373f4defa136db20 to your computer and use it in GitHub Desktop.
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)
/*
<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