Container Pattern in React-Redux

React and Redux work together for creating the frontend part of web applications. React renders the GUI elements while Redux manages the application state.

This post is a rehash of the Redux documentation for using Redux with React.

Rational

In Redux, the application state is altered by reducers which are triggered by actions. Both actions and reducers are part of Redux. A method called dispatch() is called given an action which triggers the reducers. The state is kept in a so called Redux store. A method called connect() connects a React component to Redux.

Integrating React with Redux can be done in several ways. A basic implementation might call dispatch() directly from within the React component, tighly coupling React to Redux. Another problem with this naive approach is that the separation of concerns principle is violated. The React component now manages and renders state at the same time.

It would be nice to separate the rendering from the state management which keeps the components smaller and the responsibilities clear. A elegant solution, that is currently considered best practice is to use the Container Pattern. In order to separate the concerns, the container pattern splits one React component into a React component and a JavaScript file that manages Redux. The React component strictly displays the GUI, while the JavaScript file (called the container) manages the communication to Redux wrapping the React component. The JavaScript file will execute the connect() call on the React component.

You can think of the container as a layer that sits between the GUI React component and Redux, hiding all Redux from the GUI component. Instead of calling connect() and dispatch() from within a React component directly, the container will execute all connect() and dispatch() calls.

There is a variation of the container pattern, where the container also renders GUI elements. This is not a clear separation as defined above but the option is still available. In the Redux Todos example, the AddTodo container is an example of this variation.

Implementation

In order to implement the container pattern, following parts are needed

  1. A method that creates and returns an action (called Action Creators actually one such method per action) to send into the Redux reducers.
  2. The pure React component for rendering the GUI.
  3. The container file for talking to Redux.
  4. A Redux agnostic means for getting state from the Redux store into the React component.
  5. A Redux agnostic means for altering the Redux state from within the React component.

The following code is taken from the Redux Todos examples. Just a quick explanation of what the code is supposed to do: The Todos example allows the user to add Todo items (Strings) to a list of Todos. Clicking on one of the items marks it as completed, clicking it again marks it as active again. This is referred to as toggeling.

1. Is a function that creates and returns an action. It is called an ActionCreator:

export const toggleTodo = id => ({
  type: 'TOGGLE_TODO',
  id
})

The function toggleTodo() will return a TOGGLE_TODO action. Do not put this function into the React component as actions are Redux specific and the React component should not know anything about Redux.

2. Let’s look at the TodoList component from the Redux Todos examples. Note that there is no Redux code in the component!

import React from 'react'
import PropTypes from 'prop-types'
import Todo from './Todo'

// toggleTodo is a method that the Container has put into the properties
// using a call to mapDispatchToProps. This component should call toggleTodo
// whenever it wants to toggle a TODO item.
const TodoList = ({ todos, toggleTodo }) => (
  <ul>
    {todos.map(todo =>
      <Todo
        key={todo.id}
        {...todo}
        onClick={() => toggleTodo(todo.id)}
      />
    )}
  </ul>
)

TodoList.propTypes = {
  todos: PropTypes.arrayOf(PropTypes.shape({
    id: PropTypes.number.isRequired,
    completed: PropTypes.bool.isRequired,
    text: PropTypes.string.isRequired
  }).isRequired).isRequired,
  toggleTodo: PropTypes.func.isRequired
}

export default TodoList

The first property (line 8) are all the Todo items that the TodoList has to render. The container will retrieve the Todos from the Redux store and pass them into this property (explained later)

You can see (line 8) that the component has another property, the toggleTodo() property. The container puts the toggleTodo() function from stept 1. into this property after wrapping it into a dispatch() call (explained later). This is how the React component can change the Redux state without knowing about Redux. It will just call the toggleTodo() wrapped function which triggers Redux code.

3. The third part is the container

import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
import TodoList from '../components/TodoList'
import { VisibilityFilters } from '../actions'

const getVisibleTodos = (todos, filter) => {
  switch (filter) {
    case VisibilityFilters.SHOW_ALL:
      return todos
    case VisibilityFilters.SHOW_COMPLETED:
      return todos.filter(t => t.completed)
    case VisibilityFilters.SHOW_ACTIVE:
      return todos.filter(t => !t.completed)
    default:
      throw new Error('Unknown filter: ' + filter)
  }
}

const mapStateToProps = state => ({
  todos: getVisibleTodos(state.todos, state.visibilityFilter)
})

// Put the method toggleTodo into the properties, so that the wrapped component
// can take it from the properties and use it. The toggleTodo implementation is 
// specific to Redux. It will call dispatch() using an action.
//
// The action is created using a method also called toggleTodo (I cannot imagine
// why the authors of this example though it was a good idea to call both functions
// the same although they are two different things!!! This will confuse beginners into oblivion)
const mapDispatchToProps = dispatch => ({
  toggleTodo: id => dispatch(toggleTodo(id))
})

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

The container wraps the TodoLost in a connect() call (line 34). It uses two parameters mapStateToProps() and mapDispatchToProps(). This is how the container passes parameters into the Redux component.

mapStateToProps() retrieves the Todo items (applying busines logic as in filtering the Todo items) from the Redux store and then binds them to the todos Property. The todos property then is available in the React component so it can render the Todo items. That means the React component learns about the data without knowing anyting about the Redux store. This is basically step 4. in our list of necessary items.

mapDispatchToProps() deals with step 5. It allows the React component to alter the Redux store without knowing about the Redux store. What mapDispatchToProps() does is, it binds a dispatch() function to the toggleTodo property. dispatch() calls the function from step 1. which returns a Redux action and then sends this action to the Redux store to alter it’s state.

mapStateToProps() and mapDispatchToProps() are actually methods from the official react redux binding.

At this point all five bullet points from the list are dealt with.

Summary

To recap and to summarize this post, React and Redux go together very well. In order to keep a clean code structure and follow the current best practices, the container pattern is used to integration React and Redux. A container is a JavaScript file that acts as a layer between React and Redux. The container contains all Redux specific parts and hides them from the React component that it wraps. The React component’s task is to render the GUI using the state that it gets fed from the container and to update the state using the properties that the container provides. The React component knows nothing about the container and hence it knows nothing about Redux.

As an outlook, maybe it is possible to implement a generic container that can be used to wrap all your react components. This means that you could use that container from a JS library or NPM dependency and just Redux-Enable your React component by applying that generic container to it. In Java Spring such a feature would be implemented using annotations. Maybe there is something equivalent in JavaScript?

Thank you for reading this post.

Electron Overview

Electron is an open source, cross platform library for building Desktop GUI applications with CSS, HTML and JavaScript. It is developed by GitHub and it uses Chromium and Node.js to display the GUI. Electron was devised to create GitHub’s Atom editor.

VSCode can be used as an editor on all of the platforms (Linux, Windows and MacOS). VSCode can even be used to debug Electron applications. https://electronjs.org/docs/tutorial/debugging-main-process-vscode https://github.com/octref/vscode-electron-debug