redux-ren
v1.0.0-alpha4
Published
Write react-redux without boilerplate.
Downloads
10
Readme
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 } });