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

tiny-duck

v1.1.1

Published

Composable redux reducers

Downloads

24

Readme

Tiny Duck

Composable redux reducers

Build Status npm version

Tiny Duck is a small library that allows you to define small, reusable collections of reducer actions and compose them together.

Tiny Duck gives you high code reuse and testabilty for your redux reducers.

Tiny Duck was inspired from the pattern of erikras/ducks-modular-redux where you bundle all of your actions, action types and reducers in the one module.

Getting Started

Tiny Duck is available on npm: npm install tiny-duck

In the follow examples we are going to use Tiny Duck to create an counter workflow and reuse it in multiple sub states.

Let's first start by importing TinyDuck and creating our counter workflow.

import TinyDuck from 'tiny-duck';

// Create counter workflow
const counter = {
  initialState: {
    counter: 0
  },
  UP: (state, action) => ({
    ...state,
    counter: (state.counter + 1)
  }),
  DOWN: (state, action) => ({
    ...state,
    counter: (state.counter - 1)
  })
};

The counter workflow is a plain javascript object with 3 parts.

  • initialState is a reserved word in TinyDuck allowing you to set the initial state.
  • UP and DOWN are both pure functions returning a new state, this is how you can defined your reducer actions.

Defining your actions and workflows separately, you are able to test the functions independently from your reducers.

Now that we have our workflow, we can use Tiny Duck to create our reducer and action types.

const {reducer, actions} = TinyDuck(counter);

// actions => {UP: 'UP', DOWN: 'DOWN'}

TinyDuck returns reducer and actions

  • reducer is the function you give to redux.
  • actions is an object containing all the action types defined, including all nested action types.

TinyDuck is a many arity function allowing you to pass many workflows and merge them together.

const {reducer, actions} = TinyDuck(counter, {
    RESET: (state, action) => ({counter:0})
});

// actions => {UP: 'UP', DOWN: 'DOWN', RESET: 'RESET'}

Namespaces

Optionally TinyDuck can take a string as the first argument. This string will then be used to namespace all relative actions. The default namespace is empty ''.

Namespaces with Tiny Duck work similar to URL's where you can have relative and absolute URL's you can also have relative and absolute namespaces. Absolute namespaces are created by prefixing your namespace with /.

Example:

const {reducer, actions} = TinyDuck('ns', counter);

// actions => {UP: 'ns/UP', DOWN: 'ns/DOWN'}

Tiny Duck Composition

Tiny Duck allows you to compose other TinyDuck as reducers to operate on sub portions of state.

const {reducer, actions, initialState} = TinyDuck({
   counter1: TinyDuck(counter),
   counter2: TinyDuck(counter)
});

/*
actions => {
    counter1: {UP: 'counter1/UP', DOWN: 'counter1/DOWN'}, 
    counter2: {UP: 'counter2/UP', DOWN: 'counter2/DOWN'}
}

initialState => {
    counter1: {counter:0},
    counter2: {counter:0}
}
*/

In the above example you will notice that we can also access the initialState, this allows Tiny Duck to compose and merge the actions and initialState.

In actions we can see that TinyDuck has automatically add the namespace of the sub state we declared. Eg: {UP: 'counter1/UP', DOWN: 'counter1/DOWN'}. This is how Tiny Duck can ensure isolation of action types.

When the action {type: actions.counter1.UP} is passed to the reducer, the action handler only operates on the sub state.

const newState = reducer(initialState, {type: actions.counter1.UP});

/*
newState => {
    counter1: {counter:1},
    counter2: {counter:0}
}
*/

Absolute namespaces can be used to have an action be dispatched to many different action handlers operating on different parts of your redux state.

This is useful if you want one action to impact multiple parts of your state. e.g. server events (via web sockets etc) or LOGOUT event needing many parts of state to be reset.

const {reducer, actions, initialState} = TinyDuck({
   counter1: TinyDuck('/', counter),
   counter2: TinyDuck('/', counter)
});

/*
actions => {
    counter1: {UP: '/UP', DOWN: '/DOWN'}, 
    counter2: {UP: '/UP', DOWN: '/DOWN'}
}

initialState => {
    counter1: {counter:0},
    counter2: {counter:0}
}
*/

With the absolute namespace in place both counter1 and counter2 have the same namespaced action types. This means that when {type: actions.counter1.UP} is passed to the reducer, both handers for /UP will be triggered.

const newState = reducer(initialState, {type: actions.counter1.UP});

/*
newState => {
    counter1: {counter:1},
    counter2: {counter:1}
}
*/

NOTE: The output of TinyDuck can also be passed as an argument directly to TinyDuck. This allows you to have actions with mixed namespace operating on the same subset of state.

WARNING: Absolute namespaces are a double edge sword. You need to be very careful when using them.

License

MIT