epic-react
TypeScript icon, indicating that this package has built-in type declarations

1.0.0 • Public • Published

epic-react

Not epic but handy helpers for conditional React rendering. Functional utilities to quickly implement recurring rendering patters in a readable way.

Jump directly to the epic.

Usage

npm install react epic-react

import React from 'react'
import { when } from 'epic-react'

export const DaytimeTheme = (time: number) =>
  when(
    time > 6 && time < 18,
    () => <Daylight />,
    () => <Nighttime />
  )

Available Methods

import { not, when, epic, until, list, random } from 'epic-react'

not

If the provided condition is true nothing will be rendered.

export const CartButton = (stock: number) =>
  not(stock === 0, <Button onClick={Store.addToCart}>Buy</Button>)

when

If the condition is true render the component and if it's false render the fallback if one is provided.

export const DaytimeTheme = (time: number) =>
  when(
    time > 6 && time < 18,
    () => <Daylight />,
    () => <Nighttime /> // Optional
  )

epic

Usually there is more than an if else required for rendering. In this case an epic will help:

// Usage as an object: specifying conditions along with components.
epic
  .loading(() => <p>Loading...</p>, false)
  .error(() => <p>Error...</p>, false)
  .fallback(() => <p>Fallback...</p>, false)
  .done(() => <p>Epic done</p>)

// Usage as a function: specifying conditions first.
epic({
  loading: false,
  error: false,
  fallback: false,
})
  .loading(() => <p>Loading...</p>)
  .error(() => <p>Error...</p>)
  .fallback(() => <p>Fallback...</p>)
  .done(() => <p>Epic done</p>)

The second option is especially handy if you already have an object with the conditions available or can create a matching state.

until

Asynchronous rendering depending on the state of a Promise.

until<string, null>(
  new Promise<string>((done) => setTimeout(() => done('resolved!'), 3000)),
  (result) => <p>{result}</p>,
  <p>loading...</p>
)

If the Promise is rejected an optional error handler will be rendered.

until<string, string>(
  new Promise<string>((done, fail) =>
    setTimeout(() => fail('rejected...'), 3000)
  ),
  result => (
    <p>{result}</p>
  ),
  <p>loading...</p>,
  error => (
    <p>{error}</p>
  )
)}

list

const ListElement = ({ value }: { value: number }) => <span>{value}</span>

This epic makes rendering lists quicker.

list<{ value: number }>([{ value: 1 }, { value: 2 }, { value: 3 }], ListElement)

As the third parameter you can pass an element which will be rendered in case list is empty.

list<{ value: number }>([], ListElement, <span>It's an empty list ;)</span>)

An optional separator element can be inserted in between elements, similar to the join() function for regular Arrays.

list<{ value: number }>(
  [{ value: 1 }, { value: 2 }, { value: 3 }],
  ListElement,
  <span>List is empty...</span>
  <span>,</span>
);

random

Randomly picks a component from the list of arguments.

random(
  () => <p>first</p>,
  () => <p>second</p>
)

Comparison with other Abstractions

Vanilla JS

Simply writing all the logic yourself works just fine. These epics however have been created due to very similar parts occurring over and over again.

// Vanilla JS
export const AsyncFetchedData = (data) => {
  if (data.loading) {
    return <Loading />
  }

  if (data.error) {
    return <Error />
  }

  return <Data data={data.result} />
}
// with an epic
export const AsyncFetchedData = (data) => epic
  .loading(() => <Loading />, data.loading)
  .error(() => <Error>, data.error)
  .done(() => <Data data={data.result} />);

Higher Order Components

import { Suspense } from 'react'

const LazyComponent = React.lazy(() => import('./ProfilePage'))

return (
  <Suspense fallback={<div>Loading...</div>}>
    <LazyComponent />
  </Suspense>
)
import { until } from 'epic-react'

return until(import('./lazy'), (result) => <result.default />, <p>Loading...</p>)

Suspense (HOC): 4 Lines of Code

until (react-epic): 1 Line of Code 🤓

Event Handlers

Shortcuts to do something when a certain key is pressed. To be used with onKeyDown, onKeyPress or onKeyUp.

import { onEnter, onEscape } from 'epic-react'

onEnter

<input onKeyUp={onEnter((event) => submit())} />

onEscape

<input onKeyDown={onEscape((event) => close())} />

Several Keys

<input
  onKeyPress={(event) => {
    onEnter(() => submit())(event)
    onEscape((event) => close(event))(event)
  }}
/>


epic-react

Readme

Keywords

none

Package Sidebar

Install

npm i epic-react

Weekly Downloads

1

Version

1.0.0

License

MIT

Unpacked Size

26.5 kB

Total Files

6

Last publish

Collaborators

  • naminho
  • tobua