react-compinators v1.0.33
λ⚛ React Compinators
A tiny library of functional utilities for composing React components:
compinators = Component Combinators
.
Synopsis
Create three new components by partially applying the <Label>
component
color
prop, one for each member of the COLORS
union:
import {String} from 'effect'
import {unionVariants} from 'react-compinators'
const [ GreenLabel, YellowLabel, RedLabel ] = unfoldProp(
Label, // Component that we will wrap three times.
'color', // Prop that we will partially apply.
)(
COLORS, // Array of union members.
String.capitalize, // Optional function will be used to compute variant
// displayName from its `color` prop.
)
See the tutorial for more info.
Quick Start
> pnpm add react-compinators
You can then import any of the exported functions from the package
react-compinators
. For example to import the assume
function in your
component:
import {assume} from 'react-compinators'
Why?
React offers Far More Than One Way to compose and repurpose components. For example, you can fiddle with their props and wrap them in various ways. Whatever you do, eventually you will end up with a new component. The functions here provide a lighter alternative, via functions that React calls Higher Order Components (HOCs).
Consider a colored <Label>
component with props of type:
interface LabelProps {
text: string
color: 'red' | 'yellow' | 'green'
}
If we find ten yellow labels in our code, we could create a new
<YellowLabel>
component, where the color is fixed on yellow
:
const YellowLabel = ({text: string}) => (
<Label {...{text}} color='yellow' />
)
// Using:
<YellowLabel text='Hello World!' />
Using the assumeProp
combinator from this library, we have lighter alternative that avoids JSX:
import {assumeProp} from 'react-compinators'
import type {FC} from 'react'
// Note correct computed type for YellowLabel props.
const YellowLabel: FC<{text: string}> = assumeProp(Label, {color: 'yellow'})
// Using:
<YellowLabel text='Hello World!' />
The result is exactly the same. The style of HOCs you will find here is
supported by React Dev Tools
so the debug experience of the <YellowLabel>
should similar, except it will
appear under the name <Yellow(Label)>
.
I have found these functions helpful in all kinds of situations:
- Cross-cutting concerns.
- For example when different parts of an application require functionality
such as:
- Authentication guards.
- Memoizing component props in local storage, lest they be lost on browser refresh.
- Logging
- But you would rather not touch the source code of components involved.
- For example when different parts of an application require functionality
such as:
- When more components but fewer props is preferable to
fewer components but more props.
- For example, when writing components for a design-system driven library,
it is common to create a highly configurable component, for example a
<Button>
, and then derive various variants from it, for example:<PrimaryButton>
or<SecondaryButton>
.- These variants are often just different combinations of values for the
props of the
<Button>
. - Functions like
withVariants
reduce boilerplate and clarify intent for such tasks.
- These variants are often just different combinations of values for the
props of the
- Describing changes to components as plain old data lets you manipulate
definitions as data, for example to customize a color, or to add a
debug panel overlay to all
children
of a component.
- For example, when writing components for a design-system driven library,
it is common to create a highly configurable component, for example a
- The functions here are all well-known higher-order functions, for example
curry
, that have been specialized for React components.- This helps you take pieces of components out of JSX, and into your regular functional programming pipelines. When a simple function would suffice, these combinators help your stay in a single “world”, and leave the JSX more focused on its UI concerns.
- Just as a
curry
combinator for functions is useful enough to deserve its own name, so too forassumeProps
when dealing with React components.
Features
A Contravariant
instance for Effect and a bunch of combinators. If
you squint hard you will see they are all just specializations of mapProps
:
The Combinators
appendChildren
assumeProp
assumeProps
modCssVar
mapProp
mapProps
modChildren
modProp
modStyle
omitProps
prependChildren
renameProp
renameProps
requireProp
unfoldProp
withDefault
withDefaultStyle
withStyle
withVariants
Roadmap
- Guards and branches
- Layout and children
- Debug and pointcuts
See Also
3 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago