redux-ren

1.0.0-alpha4 • Public • Published

redux-ren

Write react-redux without actions boilerplate.

Consider this an experimental proof of concept.

redux-ren takes a functional stateless react component, enriches simple state modifier functions to become redux actions and sets everything up in the background so you end up with a working react-redux+thunk app.

The following is a rewrite of the original redux counter example using redux-ren. While this is one blob of JavaScript, the Counter component and the actions are completely independent and could be moved to individual files.

import ren from 'redux-ren';
import React from 'react';
import PropTypes from 'prop-types';
 
const Counter = (props) => (
  <p>
    Clicked: {props.value} times
      {' '}
    <button onClick={props.increment}>
      +
      </button>
    {' '}
    <button onClick={props.decrement}>
      -
      </button>
    {' '}
    <button onClick={props.incrementIfOdd}>
      Increment if odd
      </button>
    {' '}
    <button onClick={props.incrementAsync}>
      Increment async
      </button>
  </p>
);
 
Counter.propTypes = {
  value: PropTypes.number.isRequired,
  increment: PropTypes.func.isRequired,
  decrement: PropTypes.func.isRequired,
  incrementIfOdd: PropTypes.func.isRequired,
  incrementAsync: PropTypes.func.isRequired
};
 
// because these two actions increment "value" based on
// the existing state, we need to use (p, state) -
// "p" is just a dummy in this case because there's no payload
// for the action so we can get "state" as the second argument.
// the functions return an object with your intended state change.
// internally this will be handled then using
// const newState = { ...state, { value: state.value + 1 } };
const increment = (p, state) => ({ value: state.value + 1 });
const decrement = (p, state) => ({ value: state.value - 1 });
 
// the two following actions demonstrate how to use the thunk middleware.
// the outer function gets passed "actions" which are the actions we
// defined here wrapped with dispatchers. just calling "increment()"
// from above wouldn't have any effect, whereas "actions.increment()"
// correctly triggers the action tied to our react/redux setup.
// the inner function is a classic thunk. because we can access
// "actions" we don't really need dispatch, but calling
// dispatch({ type: 'increment' }) would work as well.
// in this case it's just there because we need "getState"
// as a second argument.
const incrementIfOdd = (actions) => (dispatch, getState) => {
  if (getState().value % 2 !== 0) {
    actions.increment();
  }
};
 
// this is another async action. In this case we can omit "(dispatch, getState)"
// altogether because we just want to trigger another action.
const incrementAsync = (actions) => () => {
  setTimeout(actions.increment, 1000);
};
 
const actions = { increment, decrement, incrementIfOdd, incrementAsync };
ren({ id: 'app', rootComponent: Counter, actions, initialState: { value: 0 } });

Readme

Keywords

Package Sidebar

Install

npm i redux-ren

Weekly Downloads

0

Version

1.0.0-alpha4

License

Apache-2.0

Unpacked Size

347 kB

Total Files

11

Last publish

Collaborators

  • walterra