react-compinators
    Preparing search index...

    react-compinators

    λ⚛ React Compinators

    A tiny library of functional utilities for composing React components: compinators = Component Combinators.

    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.

    > 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'
    

    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:

    1. Cross-cutting concerns.
      • For example when different parts of an application require functionality such as:
        1. Authentication guards.
        2. Memoizing component props in local storage, lest they be lost on browser refresh.
        3. Logging
      • But you would rather not touch the source code of components involved.
    2. 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.
      • 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.
    3. 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 for assumeProps when dealing with React components.

    A Contravariant instance for Effect and a bunch of combinators. If you squint hard you will see they are all just specializations of mapProps:

    1. appendChildren
    2. assumeProp
    3. assumeProps
    4. modCssVar
    5. mapProp
    6. mapProps
    7. modChildren
    8. modProp
    9. modStyle
    10. omitProps
    11. prependChildren
    12. renameProp
    13. renameProps
    14. requireProp
    15. unfoldProp
    16. withDefault
    17. withDefaultStyle
    18. withStyle
    19. withVariants
    1. Guards and branches
    2. Layout and children
    3. Debug and pointcuts
    1. Tutorial
    2. API Reference
    3. recompose