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

react-apothecary

v0.5.2

Published

React UI bindings for apothecary

Downloads

10

Readme

React-Apothecary

React bindings for the apothecary state container. Use this to communicate with the apothecary strore.

Usage

The core API consists of two elements: Bridge and tunnel.

Bridge

Normally, your whole app will be wrapped in this component. It provides the apothecary store to a component tree:

import React from "react";
import { initialize } from "apothecary";
import { Bridge } from "react-apothecary";
import App from './App';

const store = initialize({ n: 1 });

export default () => <Bridge store={store}><App /></Bridge>;

tunnel

Use this HOC to connect your component to the apothecary store. The first argument is used to inject properties from the store into your component. The second argument can be used to inject mutators, which react-apothecary will automatically bind to the dispatch. Example:

import React from "react";
import { split } from "apothecary";
import { tunnel } from "react-apothecary";

const increment = () => split(n => n + 1, "n");

const decrement = () => split(n => n - 1, "n");

function Counter({ n, inc, dec }) {
  return (
    <div>
      <button onClick={dec}>-</button>{n}<button onClick={inc}>+</button>
    </div>
  );
}

export default tunnel(state => ({ n: state.n }), {
  inc: increment,
  dec: decrement
})(Counter);

Let's examine each argument to tunnel in detail.

First argument: select(state, inputProps) -> outputProps

The first argument is a function that you use to inject specific pieces of your application state into a component. In the example above, we are injecting the n variable from our application state as a prop to our Counter component.

The select function also accepts the incoming component props as a second argument. Consider this example:

export default tunnel((state, inputProps) => ({
  n: state.n + inputProps.offset || 0
}))(Counter);

Now if we were to render our Counter component with the offset prop, it would change the value of n:

<Counter offset={3} />

Assuming n is equal to 1 in the initial state, our component will render with an n equal to 4.

Second argument: mutators

The second argument is for injecting apothecary mutators into your component. The tunnel HOC will take care of binding them to the dispatch, so that your component doesn't need to keep a reference to the dispatch. This means that calling the function from the component will result in a state change in the store. There is a standard and a more advanced way to use this, both described below.

Standard Usage: Object Literals

Normally we use a flat object literal made up of higher order apothecary mutators. Let's look at the original example again:

const increment = () => split(n => n + 1, "n");

const decrement = () => split(n => n - 1, "n");

export default tunnel(state => ({ n: state.n }), {
  inc: increment,
  dec: decrement
})(Counter);

In this case our Counter component will receive inc and dec props. When these are executed, they will change the value of n in the store.

Advanced Usage: Using fromProps(inputProps, outputProps, state) -> mutators

A second way to specify the mutators is to use the fromProps function. Consider this example:

import { split } from 'apothecary';
import { fromProps } from 'react-apothecary';

const increment = step => () => split(n => n + step, "n");

const decrement = step => () => split(n => n - step, "n");

export default tunnel(state => ({ n: state.n }), fromProps(props => ({
  inc: increment(props.step),
  dec: decrement(props.step)
})))(Counter);

In this case, we'd render the component with a step prop that indicates how much n should change by when we execute our mutators:

<Counter step={5} />

In addition to the input props, the function that you pass into fromProps also accepts two more arguments. Here are all the arguments described in order:

  1. inputProps: the props passed into the component by the parent
  2. outputProps: the props that were computed as a result of the select function
  3. state: the raw apothecary state.

These are provided in case they are helpful in the act of composing your mutators. Most of the time, the first argument should be sufficient.

Contributions

TBD

Testing

TBD