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

redux-combiner

v0.4.4

Published

Convenient reducers combiner for Redux

Downloads

28

Readme

Build Status Coverage Status

redux-combiner

redux-combiner proposes a way to describe possible application state changes as a tree of reducers reacting on specific actions.

Description

A reducers tree consists of nodes, and its structure corresponds to an application state. A node describes its subtree and registers actions reducers on the node. A node must be initialized with its subtree or specific default value, this way reducers tree defines default application state. Each node of the tree returns just a normal reducer, and each such node is able to contain other nodes or plain old switch-case reducers within its subtree. All these forces decomposition, and makes reducers more focused on related state changes. This also means that you able to integrate redux-combiner gradually into your projects by substituting or wrapping your existing reducers with redux-combiner nodes.

Example

To get a better sense let's modify Redux to-do list reducers example with redux-combiner:

import { createStore } from 'redux'
import { node, demux } from 'redux-combiner'

const reducer = node({

    todos: demux(
            [],
            {
                completed: node(false)
                    .on('TOGGLE_TODO', completed => !completed)
            },
            (todos, action) => todos.findIndex(todo => todo.id === action.id)
        )
        .on('ADD_TODO', (todos, action) => [
            ...todos,
            {
                id: action.id,
                text: action.text,
                completed: false
            }
        ]),

    visibilityFilter: node('SHOW_ALL')
        .on('SET_VISIBILITY_FILTER', (filter, action) => action.filter)
})

store = createStore(reducer)

redux-combiner comes with two kinds of nodes: node and demux. node is just a normal node: it describes its subtree and registers reducers on the node. demux (demultiplexer) is a bit special one: it also expects that described node is a collection of nodes with a specific structure, and each such node can be uniquely addressed within the collection. So, from the example, we can see that todos array is described by demux node, and each item can have its property completed to be toggled on TOGGLE_TODO action. Which item to pick is determined by the action id property.

From the example we can also see that there is no need for switch-case reducers and that propagation of state changes is handled for you, though you still need to return new values from your reducers when actual changes happen (as in ADD_TODO reducer in the example).

To be efficent, redux-combiner uses information on expected actions of each reducers subtree and calls only related subtrees. So, in the example, only visibilityFilter subtree will be called on SET_VISIBILITY_FILTER action.

And that's basically it! As you can see, redux-combiner has really simple yet powerful API which can be further customized. See docs for more!

Performance

redux-combiner has quite decent performance, as js-framework-benchmark shows. It's quite close to bare React version of the benchmark.

Installation

    npm i --save redux-combiner

Documentation

combiner ( combineReducers ) -> { node, demux }

default export of redux-combiner is combiner function that creates customized nodes. combiner's only argument is combineReducers to use to combine reducers tree.

This is useful to support custom combineReducers, for example, redux-loop's one.

Please note, that only combineReducers working with plain js object are supported at the moment. For more details see limitations.

node ( initial ) -> Function (state, action)

node is a node initialized with default combineReducers.

initial describes initial state or subtree of reducers tree with some other nodes within it. Children nodes may be placed arbitrary deep within the subtree. The subtree may have primitive leafs.

demux ( initial, [ itemSchema ], [ selector ] ) -> Function (state, action)

demux is a demux node initialized with default combineReducers.

initial is similar to node's, but it's expected to be a collection of similar elements. The collection is not necessary an array, objects also may be used as collections of values.

itemSchema describes each collection item subtree.

selector is used to select item or items of the collection to apply specific action. selector may be either a function or a property name to get on an action. If selector is a function it must return either action property name, or iterator of such property names. If selector is omitted, it defaults to 'index' for array states or to 'id' for object states.

selector function signature is reducer-like: (state, action), where state corresponds to state subtree of the node.

selector should not depend on action type, because it's just a mean of addressing. If your selector depends on action type that means your addressing is inconsistent. But there may be cases when you need to select items in different ways. The suggested approach is to wrap a demux as a child of another one.

node#on ( actions, reducers ) -> node

Registers reducers on specific actions on the node. Returns the same node to allow chaining.

reducers is either a function or array of functions. If reducers is an array, than all reducers will be called on the action in order (similar to reduce-reducers).

actions is either action type or an array of action types. If actions is an array, than all corresponding reducers are called on each action in order.

combineReducers -> Function ( state, action )

redux-combiner version of combineReducers is quite similar to Redux' one. The main difference is that it supports arrays as roots of composition:


import { combineReducers } from 'redux-combiner'
import reducers from './reducers'

combineReducers([ ...reducers ])

Limitations

Currently only plain js object states are supported, because of notion overlapping between reducers tree structure and state representation. But it should be quite easy to add support for less trivial structures, such as Immutable.js structures, by splitting these concepts.