React Renderable
Small React components for conditions, lists and composition, all taking the same kind of slot.
Why
JSX has no syntax for branching, so conditions become ternaries and &&, and they nest badly:
tsx
{isLoading ? <Spinner /> : error ? <ErrorPanel error={error} /> : <Results rows={rows} />}I wrote these primitives to turn each branch into an element:
tsx
<Switch>
<Switch.Case when={isLoading}>{Spinner}</Switch.Case>
<Switch.Case when={!!error}>{() => <ErrorPanel error={error!} />}</Switch.Case>
<Switch.Default>{() => <Results rows={rows} />}</Switch.Default>
</Switch>Renderable
Every slot takes a Renderable: a component, or an element.
tsx
type Renderable = ComponentType<{ children: ReactNode }> | ReactNode;tsx
<Wrap components={[ThemeProvider]}>{children}</Wrap>
<Wrap components={[<ThemeProvider theme="dark" />]}>{children}</Wrap>Pass the component when it needs no props: it isn't evaluated until its branch renders. Pass the element when it needs props.
Inline arrows
An arrow defers a component that needs props: it only runs when its branch is taken.
tsx
const Total = ({ amount }: { amount: number }) => <strong>{amount}</strong>;
<Guard guardIf={!invoice}>{() => <Total amount={invoice!.total} />}</Guard>