That's my logo
HomeGetting StartedDefining a type systemCreating ActionsCreating ReducersCreating selectorsConnecting a componentDemoType ReferenceAPI Reference
Examples
Readme

Getting Started

This section will walk you through the main features of re-reduced with practical examples:

In the following examples we'll be building a simple counter app.

Defining a type system

[root]/examples/Counter/types.ts

export interface State {
counter: number;
}

Creating Actions

[root]/examples/Counter/actions.ts

import { createAction } from "re-reduced";
export default {
adjust: createAction<number>("ADJUST"),
decrement: createAction("DECREMENT"),
increment: createAction("INCREMENT"),
};

alternatively, actions can be created in bulk using createActions

Note that, when using createActions, the action type is infered from the action name and namespace

import { createActions } from "re-reduced";
export default createActions("COUNTER", create => ({
adjust: create.action<number>(),
decrement: create.action(),
increment: create.action(),
}));

Creating Reducers

[root]/examples/Counter/reducers.ts

import { combineReducers } from "redux";
import { createReducer, match } from "re-reduced";
import actions from "./actions";
import { State } from "./types";
const INITIAL_STATE = 0;
export const counter = createReducer<number>(
[
actions.increment.reduce(state => state + 1),
actions.decrement.reduce(state => state - 1),
actions.adjust.reduce((state, payload) => state + payload),
],
INITIAL_STATE
);
// which can also be written like:
export const counter = createReducer<number>(
[
match(actions.increment, state => state + 1),
match(actions.decrement, state => state - 1),
match(actions.adjust, (state, payload) => state + payload),
],
INITIAL_STATE
);
export default combineReducers<State>({
counter,
});

Creating selectors

Selectors in redux are functions defined in terms of the application state and perform derivation and aggregation.

reselect is the recommended library for selector composition.

import { createSelector } from "reselect";
import { State } from "./types";
export const getCounter = (state: State) => state.counter;
export const getCounterIsOdd = createSelector(
getCounter,
counter => counter % 2 !== 0
);
export const getCounterIsPositive = createSelector(
getCounter,
counter => counter >= 0
);

Connecting a component

Re-reduced provides the connectWithActions helper function for easily connecting state and actions to a component.

[root]/src/ui/containers/Counter.tsx

import * as React from "react";
import { connectWithActions } from "re-reduced";
import actions from "./actions";
import * as selectors from "./selectors";
interface Props {
count: number;
isOdd: boolean;
isPositive: boolean;
actions: typeof actions;
}
const Counter = (props: Props) => (
<section>
<button onClick={() => props.actions.decrement()}>-1</button>
<button onClick={() => props.actions.adjust(-5)}>-5</button>
<button
disabled
style={{
color: props.isPositive ? (props.isOdd ? "blue" : "green") : "red",
fontWeight: "bold",
paddingLeft: 5,
paddingRight: 5,
width: 50,
}}
>
{props.count}
</button>
<button onClick={() => props.actions.adjust(5)}>+5</button>
<button onClick={() => props.actions.increment()}>+1</button>
</section>
);
const enhance = connectWithActions<Props>(actions, {
count: selectors.getCounter,
isOdd: selectors.getCounterIsOdd,
isPositive: selectors.getCounterIsPositive,
});
export default enhance(Counter);

Note that connectWithActions does not provide 100% feature parity with react-redux's connect.

The above enhance example can be easily rewritten without connectWithActions, using connect, applySpec and bindActionCreators.

import { bindActionCreators } from "redux";
import { connect } from "react-redux";
import { applySpec } from "ramda";
const enhance = connect(
applySpec({
count: selectors.getCounter,
isOdd: selectors.getCounterIsOdd,
isPositive: selectors.getCounterIsPositive,
}),
dispatch => ({
actions: bindActionCreators(actions, dispatch),
})
);

Alternatively, from version 1.5.0, re-reduced supports hooks, using the following syntax:

import { useActions, useReduxState } from "re-reduced";
import actions from "./actions";
import * as selectors from "./selectors";
function Counter() {
const { decrement, increment, adjust } = useActions(actions);
const { count, isOdd, isPositive } = useReduxState({
count: selectors.getCounter,
isOdd: selectors.getCounterIsOdd,
isPositive: selectors.getCounterIsPositive,
});
return <div>{/* app render logic... */}</div>;
}

Demo

Using connectWithActions HOC:

Using hooks: