Skip to content

doniyor2109/redux-lightweight

Repository files navigation

redux-lightweight

This library generates actions creators, action types and reducers for you. It uses class as a syntactic sugar for generating actions and reducers.

Build Status codecov PRs Welcome GitHub

Table of Contents

Introduction

Motivation

Redux is great library which solves data management. However it introduces some boilerplate. In order to add one business logic, developer must create 3 different things (action type, action creator, reducer) and they do one thing together. That is why I have decide to create utility that allows declare them in one place. One business logic should be declared in one place.

This library is inspired by redux-actions and mobx

Getting Started

Installation

$ npm install --save redux-lightweight

or

$ yarn add redux-lightweight

Usage

Create class that has state property as initial state and methods as actions.

import { createUpdater } from 'redux-lightweight';

export class Counter {
  state = 10;
  
  increment(amount = 1) {
    return this.state + amount;
  }
  
  decrement(amount = 1) {
    return this.state - amount;
  }
}

export const [counterReducer, counterActions] = createUpdater(Counter);

counterReducer; //  reducer for Counter class
counterActions; //  action creator for Counter  class - { increment, decrement }

Usage with React Hooks

redux-lightweight exposes useUpdater custom hook to make it easier working with reducers.

import React from 'react';
import { useUpdater } from 'redux-lightweight';

import { Counter } from './Counter';

function CounterView() {
    const [counter, { increment, decrement }] = useUpdater(Counter);
    return (
        <div>
            <p>{counter}</p>
            <button onClick={() => increment()}>+</button>
            <button onClick={() => decrement()}>-</button>
        </div>
    );
}

Edit 0y50x9040v

Usage with react-redux

redux-lightweight generates simple action creators and reducer. So you can work with them as usual.

import React from 'react';
import { connect } from 'react-redux';

import { counterActions } from './Counter';

function Counter({ counter, increment, decrement }) {
    return (
        <div>
            <p>{counter}</p>
            <button onClick={increment}>+</button>
            <button onClick={decrement}>-</button>
        </div>
    );
}

const mapStateToProps = (state) => ({ counter: state });

const mapDispatchToProps = {
  increment: counterActions.increment,
  decrement: counterActions.decrement
};

export default connect(mapStateToProps, mapDispatchToProps)(Counter);

Edit 0y50x9040v

Usage with redux-saga

In order to handle redux-lightweight generated action creators in saga, you can access action type with action function itself:

import { takeEvery } from 'redux-saga/effects';

import { counterActions } from './Counter';

function* rootSaga() {
  yield takeEvery(counterActions.increment.type, incrementWorkerSaga);
}

Usage only for actions

If you have already big reducers that are difficult to migrate then you can use library as action generator.

Arguments passed to actions will be array in payload

{
  type: actionType,
  payload: args // array of arguments
}
export class Counter {
  increment(amount) {}
  
  decrement(amount) {}
}

const [, counterActions] = createUpdater(Counter);

switch(type, payload) {
   case counterActions.increment.type:
    return state + payload[0];
  case counterActions.decrement.type:
    return state - payload[0];
   default:
    return state;
}

dispatch(counterActions.increment(1));

Advanced Usage

As redux-lightweight works with classes, you can use extended classes as well. That is useful to reuse reducers and actions.

class Calculator extends Counter {
  double() {
    return this.state * 2;
  }
}

export const [calculatorReducer, calculatorActions] = createUpdater(Calculator);

Now it generates 3 action creators:

  • increment
  • decrement
  • double

How it works

Basically redux-lightweight generates action creators, action types and reducers for you.

When you pass your class to redux-lightweight, it generates following things for you:

  • Action creator - Each method of class e.g increment, decrement
  • Action type - Prefixed by class name e.g "Counter/increment"
  • Reducer - Which handles all actions inside class
    • In order to set initial state for reducer, declare state property on class.
class Counter {
  state = 10; // Initial state for reducer = 10
  
  increment(amount = 1) {
    return this.state + amount;
  }
  
  decrement(amount = 1) {
    return this.state - amount;
  }
}

const [counterReducer, counterActions] = createUpdater(Counter)
  • counterActions contains all methods of Counter class as actions. In this case there will be two actions:
counterActions.increment(100) // { type: "Counter/increment", args: [100] }

counterActions.decrement(100) // { type: "Counter/decrement", args: [100] }
  • counterReducer is reducer that handles all actions of class. It is same as with following switch/case statements:
switch(type) {
   case "Counter/increment":
    return state + amount;
  case "Counter/decrement":
    return state - amount;
   default:
    return state;
}

If you want to get action type for action then you can access it with type property of action:

counterActions.increment.type // "Counter/increment"`

API Reference

createUpdater(Updater)

Creates reducer and action creators for given Updater class. Receives class that has state property and methods.

EXAMPLE
const [reducer, actions] = createUpdater(Counter);

useUpdater(Updater)

Custom hook for using Updater. Receives class that has state property and methods.

EXAMPLE
function App() {
  const [state, actions] = useUpdater(Counter);
}

Licence

This project is licensed under the MIT License - see the LICENSE file for details