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

photonic

v0.0.5

Published

Reduce the potential energy of your React components

Downloads

6

Readme

Photonic

Conditional rendering in React using decision trees

Install

npm install --save photonic

Example

A stateful component called UserPage that fetches and renders data about a user.

import React from 'react';
import { stateful } from 'photonic';

// Define a component for each possible state of the UserPage.
const User        = ({ user }) => <div>{user.name}</div>;
const Fetching    = () => <div>Fetching...</div>;
const FetchFailed = ({ errorStr }) => <div>{errorStr}</div>;

/*
  On each render, Photonic will find the currently active node
  in the decision tree and render it. For example, the tree below
  has the following rules:
  - The first decision point has two branches: one for when state.user exists
    and one for when it is undefined.
  - When the user exists, just show the User component.
  - The undefined branch further splits into two branches:
    - Show 'Fetching' when there's no data and we're fetching the user from
      the server.
    - Show FetchFailed when there was an error fetching the data
*/
const tree = [
  {
    show: User,
    withProps: ({ state }) => ({ user: state.user }),
    when: ({ state }) => state.user !== undefined
  },
  {
    when: ({ state }) => state.user === undefined,
    show: [
      {
        show: Fetching,
        when: ({ state }) => state.fetching
      },
      {
        show: FetchFailed,
        withProps: ({ props }) => ({ errorStr: props.errorStr }),
        when: ({ state }) => !state.loading && state.fetchFailed
      }    
    ]
  }
];

class UserPage extends React.Component {
  componentWillMount() {
    this.setState({ fetching: true });
    fetchUser()
      .then(user => this.setState({ user, fetchFailed: false, fetching: false }))
      .fail(() => this.setState({ fetchFailed: true, fetching: false }));
  }

  render() {
    return stateful(this, tree)();
  }
}

API

nodes

A node is an object that describes a decision point in the decision tree.

{
  show:      a React component (for leaf nodes) or another tree
  withProps: props to pass to `show` (for leaf nodes)
  when:      boolean condition
}

You can think of the keys as a little story: Render show with the props withProps if when is true.

These are the possible values for each key:

{
  show:      React component
  withProps: object | function returning object | undefined
  when:      boolean | function returning boolean
}

In dev mode, Photonic will check the when condition for all branches out of a node. If multiple branches from one node are active then Photonic will throw a warning to let the developer know that the branches are not exclusive. In production, it picks the first active branch and returns for better performance..

stateful

Call this function with your component instance and a decision tree. It will render the active node.

import { stateful } from 'photonic';
const tree = [/*...*/];
class ImStateful extends React.Component {
  render() {
    return stateful(this, tree);
  }
}

sfc

You can also define stateless functional components.

import React from 'react';
import { sfc } from 'photonic';

export const FooOrBar = sfc([
  {
    show: Foo,
    when: ({ foo }) => foo === true
  },
  {
    show: Bar,
    when: ({ foo }) => !foo
  }
]);

Photonic uses order independent matching to determine which node is active. This means that you cannot assume that the first branch returned false when you are writing the condition for the second branch for a given node. I.e. each when condition must independently determine if the branch is active. This helps you to identify when states are actually independent or if they can be combined into a single state.

const tree = [
  {
    show: Foo,
    when: ({ state }) => state.a
  },
  {
    show: Bar,
    when: ({ state }) => {
      // This condition cannot assume that it is run after the
      // `when` condition from Foo just because it comes after it in this array.
      // e.g. it cannot assume that `state.a` is false.
      return !state.a;
    }
  }
]

Detecting overlapping branches

If you accidentally write overlapping branches (i.e. multiple return true for some state) then Photonic will throw a warning in the console (in dev mode only). For example, both Foo and Bar will be active if state.a < 10.

const tree = [
  {
    show: Foo,
    when: {{ state }} => state.a < 5,
  },
  {
    show: Bar,
    when: ({ state }) => state.a < 10
  }
]