npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

epic-react

v1.0.0

Published

Not epic but handy helpers for conditional React rendering.

Downloads

5

Readme

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)
  }}
/>