Skip to content

carlosrberto/reduxed

Repository files navigation

Build Status Coverage Status Maintainability

Reduxed

Reduxed is a Redux helper library for creating type constants, actions, reducers and more without all Redux boilerplate.

Why?

Because Redux has a lot of boilerplate and we always see ourselves doing repetitive tasks like:

  • Creating action type constants
  • Creating action creators
  • Creating reducers with lots of switch case statements
  • Splitting all these things in many files (actions.js, types.js, reducer.js, constants.js, etc...)

Or sometimes we need a way to reuse reducers logic and Redux don't provides a native way to do this.

Reduxed solves the above problems.

Read more

You can read a more in-depth introduction about Reduxed in the article below:

Reduxed  -  Reduced Redux Boilerplate

Installation

npm install --save reduxed

Getting started

Let's see an example without Reduxed.

// types
export const INCREMENT = 'app/counter/increment';
export const DECREMENT = 'app/counter/decrement';

// action creators
export const increment = (value = 1) => ({ type: INCREMENT, payload: value });
export const decrement = (value = 1) => ({ type: DECREMENT, payload: value });

const initialState = 0;

// reducer
export const reducer = (state = initialState, action) => {
  switch (action.type) {
    case INCREMENT:
      return state + action.payload;

    case DECREMENT:
      return state - action.payload;

    default:
      return state;
  }
}

Now let's see the same using Reduxed:

import { create, handler, getActions, getReducer, getTypes } from "reduxed";

const initialState = 0;
const options = { typePrefix: "app/counter" };

const counter = create(
  handler("increment", (state, payload = 1) => state + payload),
  handler("decrement", (state, payload = 1) => state - payload)
)(initialState, options); // options are optional

export const reducer = getReducer(counter);
export const actions = getActions(counter);
export const types = getTypes(counter);

Then you can use your reducer, actions and types like you normally do.

Explaining

getReducer will return a Redux like reducer function that accepts a state and action as arguments:

reducer(1, { type: 'app/counter/INCREMENT' }) // 2

getActions will return an object like the following:

{
  increment: payload => ({ type: 'app/counter/INCREMENT', payload }),
  decrement: payload => ({ type: 'app/counter/DECREMENT', payload }),
}

getTypes will return an object like the following:

{
  increment: 'app/counter/INCREMENT',
  decrement: 'app/counter/DECREMENT',
}

Reusing reducer logic

If you need to reuse reducers logic across your application you can use withScope from Reduxed:

import { combineReducers } from 'redux';
import { withScope } from 'reduxed';
import { reducer } from './counter';

const rootReducer = combineReducers({
  counterA: withScope('A', reducer),
  counterB: withScope('B', reducer),
  counterC: withScope('C', reducer),
});

Then in your mapDispatchToProps you can do something like this:

import { withScope } from 'reduxed';
import { bindActionCreators } from 'redux';
import { actions } from './counter';

const mapDispatchToProps = (dispatch, ownProps) => {
  const scopedActions = withScope(ownProps.scope, actions);
  return bindActionCreators(scopedActions, dispatch);
}

In your components:

const Counters = () => (
  <div>
    <Counter scope="A" />
    <Counter scope="B" />
    <Counter scope="C" />
  </div>
);

Try it

Simple counter:

Edit Reduxed - Simple Counter

Multiple counters with scope:

Edit Reduxed -  Counter with scope