Modular and easy-to-grasp redux based state management, with least boilerplate
JavaScript HTML CSS
Switch branches/tags
Nothing to show
Clone or download
anish000kumar Merge pull request #20 from binocarlos/master
#19 - fix bug to register extra sagas passed in via config
Latest commit 9c866da Jun 18, 2018


Redux Box

Setting up and organizing a redux store in your react/react-native projects can be a tedious and daunting task. Redux-Box aims at abstracting away the complexity in using redux with redux-saga, while letting you manage application state in modular fashion, without losing the flexibility or without introducing new bizarre terms.


Illustration by Vikas

Table of contents:

What's it for:

  1. Clean, expressive and minimal reducers: If you prefer keeping your code expressive, you will feel right at home with redux-box. Have a look at a simple reducer written with and without redux-box:


If you are concerned about the state getting mutated directly in the snippet above, then you need not be. Because the state being passed to a mutation is NOT the actual state object of application, instead it's a Proxy of the state. Redux-box relies on wonderful immer library to achieve the expressiveness you see above.

  1. Organise your giant state into modules
  2. Setup redux+redux-saga for our react/react-native app in a trice
  3. Simplified Sagas
  4. Just import and use store: You wouldn't need to write a dedicated HOC to interact with your store. If you need to interact with a particular store-module, you can simply import it and use it. As simple as that! Redux box offers two ways of using a module in your component : using @connectStore decorator or using render props. (refer to the usage section for better reference)


npm install --save redux-box 


yarn add redux-box 

Note for React Native:

To support the latest decorator and generator syntax, you would want to use the .babelrc file as below:

  "presets": [
  "env": {
    "development": {
      "plugins": [
    "production": {
      "plugins": ["transform-remove-console"]

The Basics

Redux box emphasizes on dividing the whole application into multiple modules. Each of these modules manages it's state seperately, with the help of 5 segments (You can skip the segments you don't need in your project):

  1. state (It specifies the initial state of the module)

  2. mutations (It specifies the function to be run when a specific action is dispatched, it's same as reducer but clutter-free)

  3. actions (it contains the actionCreators for your store. Each method of this object must return an action object )

  4. sagas (this is where you write all your sagas / async operations)

  5. selectors ( selectors can be thought of as getters or computed properties from your state)


step 1: create a module

Make sure you specify a unique name for each module ('user' in this example)

// store/user.js
import { createSagas, createContainer } from "redux-box";
import { call } from "redux-saga/effects";

const state = {
  name: "John",
  email: "",
  todos: [{ name: "First", type: 1 }, { name: "Second", type: 0 }]

const actions = {
  setName: name => ({ type: "SET_NAME", name }),
  setEmail: email => ({ type: "SET_EMAIL", email })

const mutations = {
  SET_NAME: (state, action) => ( =,
  SET_EMAIL: (state, action) => ( =

const sagas = createSagas({
  SET_EMAIL: function*(action) {
    const response = yield call(api.updateEmail,;

const getTodos = (state) => state.todos

const getCompletedTodos = createSelector( getTodos, (todos) => {
    return  todos.filter(todo => todo.type==1)

// include the ones you would like to access in your components here
const selectors = {

export const module = {
  name: "user",

//OPTIONAL: if you want to access this module using render props in your components:
export default createContainer(module);

NOTE: There also exists an optional shorthand to create actions rapidly, like so:

import {createActions, using} from 'redux-box'

const actions= createActions({
  setName: using('name'),
  setEmail: using('email')

The actionCreators generated by this code are same as the ones generated by the above code.

step 2 : register the module in redux store

import { createStore } from "redux-box";
import { module as userModule } from "./user";
import { module as postModule } from "./post";

export default createStore([userModule, postModule]);

OPTIONAL: if you need to create store with some reducers and middlewares, the signature of createStore method from redux-box goes like this:(if you have already included a module in modules array, you need NOT to register it's sagas or reducers manually by including in config object)

import { moduleToReducer } from "redux-box";

createStore((modules: Array), (config: Object));

//example config object
config = {

  //define redux middlewares
  middlewares: [],
   //define the default state for your store
  preloadedState: {},

  // sagas to be manually registered
  sagas: [userModule.sagas, testModule.sagas],

  // reducers to be manually registered
  reducers: {
    user: moduleToReducer(user)
  decorateReducer: reducer => {
    //do something
    return newReducer;
  //overrite the compose function
  composeRedux: (composer) => {
    // do something
    // return modified compose function
  // Dynamically decide when to enable or disable dev-tools 
  enableDevTools: () => true

After this you would need to wrap your root component around the Provider tag like so :

import React from "react";
import { Provider } from "react-redux";
import store from "./store";
import RootComponent from "./components/RootComponent";

class App extends React.component {
  render() {
    return (
      <Provider store={store}>
        <RootComponent />

export default App;

step 3: Use the module in component

through decorator

import React, { Component } from "react";
import { module as userModule } from "store/user";
import { connectStore } from "redux-box";

  user: userModule //  AppComponent receives 'user' as a prop
export default class AppComponent extends Component {
  componentDidMount() {
	    name : 'John',
	    email : '',
	    getTodos: [{ name: "First", type: 1 }, { name: "Second", type: 0 }],
	    getCompletedTodos: [{ name: "First", type: 1 }],
	    setName : fn(arg),
	    setEmail : fn(arg)

  render() {
    const { user } = this.props;
    return (
	<button onClick={()=>{ 
	  user.setName('jane doe')
	}}> Change Name </button>

or through render props

import React, {Component} from 'react'
import UserModule from 'store/user'

export default class AppComponent extends Component{
      {(user)=> (
        <p> {} </p>
	<p> {} </p>

Live Examples

Here are some examples to let you play around with redux-box

  1. Basic example -
  2. Example showing redux-saga usage: -
  3. Example usage with redux-form:
  4. Example usage with redux-persist :
  5. Example showing usage of preloaded state for SSR:
  6. Using redux-observable:

Upcoming Features

No pending feature requests

Suggest a new feature here


  1. Decorators aren't working

Decorators aren't still a part of es6. To use the decorator syntax you should be using a transpiler like babel. Also, in create-react-app projects the .babelrc file doesn't really work so you would need to run npm run eject to be able to use custom babel-plugins. Following .babelrc should suffice:

  "plugins": ["transform-decorators-legacy", "styled-components"],
  "presets": [ "react","es2015", "stage-2" ]

In case you wouldn't like to eject, you can still use redux-box without decorators. Like so:

 ui: uiModule
class TestComponent extends React.Component{
export default TestComponent

Above snippet is equivalent to:

class TestComponent extends React.Component{

export default connectStore({
 ui: uiModule
  1. Can I use all the features of redux-box, with createStore from redux instead?

Yes, you can! Here's the script showing how you can use createStore from redux, to setup your modules (with reducers, sagas and middlewares): (v1.3.9 onwards)

import { applyMiddleware, combineReducers, compose, createStore } from "redux";
import createSagaMiddleware from "redux-saga";
import { all } from "redux-saga/effects";
import { moduleToReducer } from "redux-box";
import { module as homeModule } from "./home";
import { module as userModule } from "./user";

//hook up your module reducers
const combinedReducer = combineReducers({
  home: moduleToReducer(homeModule),
  user: moduleToReducer(userModule)

// hook up your module sagas
const sagas = [...homeModule.sagas, ...userModule.sagas];

// hook up your middlewares here
const sagaMiddleware = createSagaMiddleware();
const middlewares = [sagaMiddleware];

//what follows below is the usual approach of setting up store
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
let enhancer = composeEnhancers(applyMiddleware(...middlewares));

function* rootSaga() {
  yield all(sagas);

const store = createStore(combinedReducer, enhancer);;
export default store;