Using redux without wasting time writing boilerplate code


stars 🌟issues ⚠️updated 🛠created 🐣size 🏋️‍♀️
00Aug 23, 2018Feb 21, 2018Minified + gzip package size for @gxl/redux-model in KB



Why creating this package

Using redux involves writing too many lines of boilerplate code, and it annoys me. So I decided to make things easy, and in the mean time respecting all the core concepts of redux.


npm install @gxl/redux-model or yarn add @gxl/redux-model

How to use

Let's start by this simple example.

You can also view this example running at https://codesandbox.io/s/my241lzk4j

import "babel-polyfill";
import React from "react";
import { render } from "react-dom";
import { Provider } from "react-redux";
import createSagaMiddleware from "redux-saga";
import { createStore, compose, applyMiddleware } from "redux";
import {
} from "@gxl/redux-model";

const service = {
  updateCount(num) {
    return new Promise(resolve => {
      setTimeout(() => {
      }, 1000);

const model = createModel({
  namespace: "home",
  state: {
    count: 0
  watch: {
    count(val) {
      console.log("val changed", val);
  // every computation corresponds to a pair of action creator and reducer
  // and you can call model[computation_name] to trigger the action
  // no need to manually bind action creators to dispatch
  computations: {
    updateCount(state, count) {
      return {
  // every effect corresponds to an action creator, when called via model[effect_name],
  // an action will be dispatched, and the effect will be triggered
  // and effects is handled by redux saga
  effects: {
    *updateCountAsync(count) {
      const num = yield service.updateCount(count);

const models = [model];
const reducer = extractReducer(models);
const sagaMiddleware = createSagaMiddleware();
const enhancers = [applyMiddleware(...[sagaMiddleware])];
const saga = extractSaga(models);
const store = createStore(reducer, {}, compose(...enhancers));

// we have to put this after saga is running, or watch will not work
feedStore(store, models);

const Counter = props => {
  return (
      <button onClick={() => model.updateCount(props.count - 1)}>Minus</button>
      <button onClick={() => model.updateCount(props.count + 1)}>Add</button>
      <button onClick={() => model.updateCountAsync(props.count + 1)}>

// similar to react-redux's connect, we mapped state[namespace] to props by default
// you can change this behavior by passing the 2nd arg to connect, which is `mapStateToProps`
const ConnectedCounter = model.connect(Counter);

  <Provider store={store}>
    <ConnectedCounter />

If you find any bugs or have a feature request, please open an issue on github!

The npm package download data comes from npm's download counts api and package details come from npms.io.