Skip to content

Instantly share code, notes, and snippets.

@GeorgeCht
Created January 6, 2025 12:54
Show Gist options
  • Save GeorgeCht/0bfccd0189b8c14abd1a108674528cce to your computer and use it in GitHub Desktop.
Save GeorgeCht/0bfccd0189b8c14abd1a108674528cce to your computer and use it in GitHub Desktop.
SolidJS Utility Components in React
/**
* Renders a list of items from an array. If the array is empty, renders the
* `fallback` if provided.
*
* @param {Array<T>} each The array of items to render.
* @param {ReactNode} fallback An optional element to render if the array is empty.
* @param {(item: T, index: number) => U} children A function that takes an item and its index and returns a React element.
*
* @example
* ```tsx
* // πŸ₯± pure jsx
* {items.length > 0
* ? items.map((item, index) => <Item key={index} item={item} />)
* : <div>No items</div>
* }
*
* // πŸ‘‰ with <For />
* <For each={items} fallback={<div>No items</div>}>
* {(item, index) => <Item key={index} item={item} />}
* </For>
* ```
*/
export function For<T, U extends React.ReactNode>(props: {
each: Array<T>
fallback?: React.ReactNode | undefined
children: (item: T, index: number) => U
}): React.ReactElement {
return (
<React.Fragment>
{props.each
? props.each.map((item, index) => props.children(item, index))
: props.fallback}
</React.Fragment>
)
}
/**
* Conditionally renders the given children if the `when` prop is truthy.
*
* If the `when` prop is falsy, renders the `fallback` prop instead if it is
* provided.
*
* If the `children` prop is a function, it is called with the value of the
* `when` prop as its argument. Otherwise, the `children` prop is rendered
* directly.
*
* Similar to the ternary operator `when ? children : fallback` but ideal for templating JSX.
*
* @param {T | undefined | null | false} when The condition to evaluate.
* @param {ReactNode} fallback An optional element fallback.
* @param {ReactNode | ((item: T) => ReactNode)} children The element to render if `when` is truthy.
*
* @example
* ```tsx
* // πŸ₯± pure jsx
* {condition ? <True /> : <False />}
*
* // πŸ‘‰ with <Show />
* <Show when={condition} fallback={<False />}>
* <True />
* </Show>
*
* // πŸ‘‰ keying with <Show />
* <Show when={session.user} fallback={<div>Not logged in</div>}>
* {(user) => <div>Hello, {user.name}</div>}
* </Show>
* ```
*/
export function Show<T>(props: {
when: T | undefined | null | false
fallback?: React.ReactNode | undefined
children: React.ReactNode | ((item: T) => React.ReactNode)
}): React.ReactElement {
return (
<React.Fragment>
{props.when
? typeof props.children === 'function'
? props.children(props.when)
: props.children
: props.fallback}
</React.Fragment>
)
}
/**
* Conditionally renders the given children if the `when` prop is truthy.
*
* If the `children` prop is a function, it is called with the value of the
* `when` prop as its argument. Otherwise, the `children` prop is rendered
* directly.
*
* @param {T | undefined | null | false} when The condition to evaluate.
* @param {ReactNode | ((item: T) => ReactNode)} children The element to render if `when` is truthy.
*/
export function Match<T>(props: {
when: T | undefined | null | false
children: React.ReactNode | ((item: T) => React.ReactNode)
}): React.ReactElement | null {
if (!props.when) return null
return (
<React.Fragment>
{typeof props.children === 'function'
? props.children(props.when)
: props.children}
</React.Fragment>
)
}
/**
* Conditionally renders the first {@link Match} child with a truthy `when` prop.
*
* If none of the {@link Match} children have a truthy `when` prop, renders the
* `fallback` prop if it is provided.
*
* @param {ReactNode} children The children to evaluate, expected to be {@link Match} elements.
* @param {ReactNode} fallback An optional element to render if no {@link Match} children have a truthy `when` prop.
*
* @example
* ```tsx
* // πŸ₯± pure jsx
* if (route === "home") {
* return <div>Home</div>
* }
* if (route === "settings") {
* return <div>Settings</div>
* }
* return <div>Not found</div>
*
* // πŸ‘‰ with <Switch />
* <Switch fallback={<div>Not found</div>}>
* <Match when={route === "home"}>
* <Home />
* </Match>
* <Match when={route === "settings"}>
* <Settings />
* </Match>
* </Switch>
* ```
*/
export function Switch(props: {
fallback?: React.ReactNode
children:
| React.ReactElement<typeof Match>
| Array<React.ReactElement<typeof Match>>
}): React.ReactElement {
const match: React.ReactNode | undefined = React.Children.toArray(
props.children,
).find((child) => {
if (React.isValidElement(child) && child.type === Match) {
return child.props.when
}
return false
})
return (
<React.Fragment>
{match && React.isValidElement(match) ? match : props.fallback}
</React.Fragment>
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment