Introducing Apothecary: Your Local, Friendly Storekeeper

Apothecary is a lightweight Flux implementation based on the popular redux library. It has no reducers, no dependencies, and can easily work with multiple UI technologies.

At risk of stating the obvious, Redux is great. But sometimes you just don’t need it. Local state will take you a long way, but it can get unwieldy when it needs to be shared or persisted. You might want something in between those extremes. Apothecary is here to help.

Apothe-what now?

It’s a name I like. Naming stuff is hard. But, according to some etymology site:

apothecary (n.)

mid-14c., “shopkeeper,” especially “pharmacist; one who stores, compounds, and sells medicaments,” from Old French apotecaire (13c., Modern French apothicaire), from Late Latin apothecarius”storekeeper”

So it’s a storekeeper. Get it?

Ok ok, so what’s the big diff?

The drumbeat’s familiar but has its own style and flavor. It’s inspired by redux and two lesser known libraries, redux-zero and deduce, so it borrows ideas from all three and adds just a ladle of special sauce. The key points:

  • No reducers. Actions themselves describe the state change.
  • Use as many stores as you need.
  • Asynchronous actions are built in.
  • Actions can easily operate on just a small subset of a large state tree.
  • Functional Programming FTW!

Let’s have some code then!

Here’s a demo of a simple increment/decrement app that demonstrates some of the more advanced concepts.

This simple snippet is about as advanced as it gets. Let’s go over each part in some detail.

Create the store

First we create the store, which will be passed into the Bridge component that wraps our app.

Define actions

Next we define some actions that will describe how the state will change when they’re executed.

These actions will result in incrementing or decrementing the variable n by the number in the step argument. Notice the split calls. This is what allows us to drill down into the piece of state that we want to modify. Without split, we’d have to define the action like this:

const increment = step => state => ({ 
...state,
n: state.n + step
});

The next step is to connect a component to the apothecary store.

Tunneling in

Using the tunnel HOC, we can inject state and actions into any component.

The first argument to tunnel is a function lets us inject data from the store as component props. It also accepts the incoming component props. In this case we use the offset prop to offset the value of n in the store by whatever the parent wants.

The second argument is used to bind actions to the dispatch and inject them into the component. There are two ways to assemble this second argument. The method shown above is the more advanced of the two; it uses fromProps, which allows you to declare a function that will assemble the actions from the incoming props. In this case, the parent is rendering our component with a step prop that indicates how much to increment by.

The simpler way to use the second argument is with a flat object literal. If we didn’t need any props from the parent, we could do this instead:

Now for the simplest part: a presentational component.

I like ’em dumb!

Components, that is. Functional, presentational components are easier to test, maintain, and reason about. That’s a big win. Let’s see ours.

Couldn’t be simpler.

All together now!

All in all, it’s really not much code:

That’s it!

Conclusion

Much gratitude to Dan Abramov, Matheus Lima, and Shannon Moeller for the inspiration. My work was made possible by theirs.

This library was for fun, but it might just be useful. If you dig it, throw some stars my way and share this post. Thanks for reading!

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.