---
status: "published"
title: "Exploring Unidirectional Components in Mithril (part 2 — Redux)"
date: "2017-10-09"
description: "Continuing the experiment from part 1, this time using Redux and the reducer pattern for unidirectional data flow in Mithril, and comparing it to Hyperapp."
image: "https://github.com/user-attachments/assets/1f452536-d907-466e-a848-4c895b1709d0"
imageAlt: "Unidirectional data flow"
author: "Vlad Sabev"
authorUrl: "https://github.com/vdsabev"
authorAvatar: "https://github.com/vdsabev.png"
tags: ["hyperapp","javascript","mithril","redux","software development"]
navigationIndex: 0
series: "Exploring Unidirectional Components in Mithril"
---

In [part 1 of this post](https://vdsabev.github.io/exploring-unidirectional-components-in-mithril-part-1-hyperapp), I described how we could morph the [Mithril](https://mithril.js.org/) library into a [Hyperapp](https://hyperapp.js.org/) lookalike to achieve unidirectional data flow. This time, I will use [Redux](http://redux.js.org/) with the reducer pattern instead, and compare the resulting code to the Hyperapp architecture.

**Disclaimer:** The Redux docs [specifically advise against using multiple Redux stores](http://redux.js.org/docs/faq/StoreSetup.html#store-setup-multiple-stores), which is what we’re doing here. When writing real applications — listen to the docs, folks! When playing with code — break the rules a little bit — it’s where learning happens.

<img width="325" height="375" alt="A mechanical counter" src="https://github.com/user-attachments/assets/3eabc8bc-96d0-4883-9a39-d054cb7bf4ef" />

## Need a Counter?

We’ll dive straight into the code and try to explain how exactly the details are implemented behind the scenes a bit later.

First of all, let’s take a quick look at the view function for our beloved Counter component, which we’ll reuse in both the Hyperapp and Redux architectures:

```jsx
const CounterView = (vnode, { count }, actions) => (
  <div>
    <h1>{count}</h1>
    <button onclick={actions.decrement} disabled={count <= 0}>-</button>
    <button onclick={actions.increment}>+</button>
  </div>
);
```

*(if this is all new to you, now is the time to catch up with *[*part 1 of this post*](https://vdsabev.github.io/exploring-unidirectional-components-in-mithril-part-1-hyperapp)*)*

And here are the components themselves:

### Hyperapp architecture

```javascript
const Counter = component({
  state: {
    count: 0
  },
  actions: {
    decrement: ({ count }) => ({ count: count - 1 }),
    increment: ({ count }) => ({ count: count + 1 })
  },
  view: CounterView
});
```

### Redux architecture

```javascript
const Counter = component({
  reducers: {
    count(state = 0, action) {
      switch (action.type) {
        case 'DECREMENT': return state - 1;
        case 'INCREMENT': return state + 1;
      }
      return state;
    }
  },
  actions: {
    decrement: () => ({ type: 'DECREMENT' }),
    increment: () => ({ type: 'INCREMENT' })
  },
  view: CounterView
});
```

If this looks sоmewhat long and verbose to you, don’t worry — we’ll make it a bit shorter later.

<img width="125" height="125" alt="Parallel lines" src="https://github.com/user-attachments/assets/4b5a9641-96b3-4450-ac90-cb3355560f3e" />

## Parallels and opposites

Both the Elm architecture (used in Hyperapp) and Redux have similar goals — reduce complexity, increase code clarity, and avoid direct state manipulation.

### Hyperapp architecture

The fundamental difference I can see is that in Hyperapp, actions are more complex functions that handle the logic and return all changes across the state.

I find this approach to be particularly useful when the effects of an action are relatively well known in advance — for example, clicking the + or - button of a counter, or rendering different views depending on whether the user is logged in or out.

### Redux architecture

In Redux, [actions are meant to be really dumb](http://redux.js.org/docs/basics/Actions.html), returning a simple object with only the minimal data for the reducer, where the real logic lies.

In addition to handling actions whose effects are well-known in advance, it also works great for the specific use case where a single action could cause various changes across the whole application.

For example, in a real-time application, receiving a notification could do all of the following:

1. Update a counter in the header
2. Show the number of unread notifications in the page title wrapped in parentheses, thus flashing the browser tab (think Gmail)
3. Show a toast notification
4. Show a browser desktop notification (if the user is on another tab)

With Redux reducers, we can dispatch an action called `NOTIFICATION_RECEIVED` or `USER_LOGGED_IN`, then handle the specific logic in each reducer, changing the data.

With Hyperapp, the best way I could think of is using an event bus. One of the things I love the most about Hyperapp is that it‘s really flexible and allows you to use all kinds of different patterns to write your application!

<img width="398" height="250" alt="Lost in contemplation" src="https://github.com/user-attachments/assets/38755d4c-2130-43e0-bc44-1970871e264a" />

## Refactoring opportunities

As always, our initial code can be made more reusable through some simple refactoring. This is where the functional-oriented approach of both architectures shines.

### Hyperapp architecture

Here, we can extract the similar counter logic in a function:

```javascript
const addToCount = (value) => ({ count }) => ({ count: count + value });...
  actions: {
    decrement: addToCount(-1),
    increment: addToCount(1)
  },
...
```

Or use an even more generic approach:

```javascript
const add = (key, value) => (state) => ({ [key]: state[key] + value });...
  actions: {
    decrement: add('count', -1),
    increment: add('count', 1)
  },
...
```

### Redux architecture

First, we can reduce the boilerplate by avoiding `switch` statements or explicitly returning `state` when the reducer doesn’t match the dispatched action:

```javascript
const Counter = component({
  reducers: {
    count: reducer(0, {
      DECREMENT: (count) => count - 1,
      INCREMENT: (count) => count + 1
    })
  },
  actions: {
    decrement: () => ({ type: 'DECREMENT' }),
    increment: () => ({ type: 'INCREMENT' })
  },
  view: CounterView
});
```

As you can see, the resulting code is somewhat shorter, easier to read, and close to the Hyperapp example. Here’s what the `reducer` function looks like:

```javascript
const reducer = (initialState, handlers) =>
  (state = initialState, action, rootState, actions) => {
    const handler = handlers && handlers[action.type];
    if (handler) {
      return handler(state, action, rootState, actions);
    }
    return state;
  };
```

It’s basically a copy of the `createReducer` function described in the [Redux docs](http://redux.js.org/docs/recipes/ReducingBoilerplate.html#generating-reducers) — the first parameter is the initial reducer value, and the second is an object with all actions and the resulting changes.

Then, we can create a higher level event called `ADD_TO_COUNT` to utilize the [Action Creator pattern](http://redux.js.org/docs/basics/Actions.html#action-creators):

```javascript
const addToCount = (value) => () => ({ type: 'ADD_TO_COUNT', value });const Counter = component({
  reducers: {
    count: reducer(0, {
      ADD_TO_COUNT: (count, action) => count + action.value
    })
  },
  actions: {
    decrement: addToCount(-1),
    increment: addToCount(1)
  },
  view: CounterView
});
```

*(actually, that’s an Action Creator Creator, but anyway)*

As you can see, both architectures are conducive to breaking the state down into small, predictable, and testable functions.

## Implementation

Now that we’ve seen what Mithril and Redux can do together, let’s see how this actually works behind the scenes:

```javascript
const component = ({ actions, reducers, events, view }) => (vnode) => {
  // Create functions which dispatch the actions to the store
  const actionDispatchers = {};
  Object.keys(actions).forEach((key) => {
    actionDispatchers[key] = (...args) => {
      store.dispatch(actions[key](...args));
    };
  });
  
  // Reducer proxies are called with the state and action proxies as additional parameters
  const reducerProxy = (state = {}, action) => {
    const newState = {};
    Object.keys(reducers).forEach((key) => {
      newState[key] = reducers[key](state[key], action, state, actionDispatchers);
    });
    return newState;
  };
  
  // Create store with initial values from component attributes
  const store = Redux.createStore(reducerProxy, vnode.attrs);
  
  // The store conveniently redraws the view when data changes
  store.subscribe(m.redraw);
  
  return {
    ...events,
    view: () => view(vnode, store.getState(), actionDispatchers)
  };
};
```

## Conclusion

Much like the Hyperapp-like architecture described in [part 1 of this post](https://vdsabev.github.io/exploring-unidirectional-components-in-mithril-part-1-hyperapp), this one has some of the same caveats — it’s still Mithril, not serializable, not completely type safe (if you’re into TypeScript), and not battle-tested.

But most of all, like I said in the initial disclaimer, having multiple Redux stores is not advised. So don’t use this in production!

*(but if you do, please let me know how it turned out, you little rebel :))*

## Resources

- An up to date [implementation of the ](https://codepen.io/vdsabev/pen/EvwNyO)`component`[ function](https://codepen.io/vdsabev/pen/EvwNyO)
- A more complex component — [Stopwatch](https://codepen.io/vdsabev/pen/BdwQWp)
- [All examples used across this series of posts](https://codepen.io/collection/XRKPpa/)


