Testing with Jest

The Redux Documentation declares Jest as the unit testing framework of choice. This is a beginners introduction to Jest.

Taken from the Jest documentation:

Zero configuration – Jest is already configured when you use create-react-app or react-native init to create your React and React Native projects. Place your tests in a __tests__ folder, or name your test files with a .spec.js or .test.js extension. Whatever you prefer, Jest will find and run your tests.

As it turns out, Jest is already integrated into your codebase should you have used create-react-app.

Error fsevents unavailable

When npm run fails with the following output:

npm test

> cryptofrontend@0.1.0 test /Users/bischowg/dev/react/cryptofrontend
> react-scripts test

Error: `fsevents` unavailable (this watcher can only be used on Darwin)
    at new FSEventsWatcher (/Users/bischowg/dev/react/cryptofrontend/node_modules/sane/src/fsevents_watcher.js:41:11)
    at createWatcher (/Users/bischowg/dev/react/cryptofrontend/node_modules/jest-haste-map/build/index.js:780:23)
    at Array.map (<anonymous>)
    at HasteMap._watch (/Users/bischowg/dev/react/cryptofrontend/node_modules/jest-haste-map/build/index.js:936:44)
    at _buildPromise._buildFileMap.then.then.hasteMap (/Users/bischowg/dev/react/cryptofrontend/node_modules/jest-haste-map/build/index.js:355:23)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:160:7)
npm ERR! Test failed.  See above for more details.

read https://github.com/expo/expo/issues/854

npm r -g watchman
brew install watchman

I had to run the brew command three times before it finally worked. npm test should now work without issues.

Testing Action Creators

Given a file actions.js that contains the action creator

function receiveEntriesActionCreator(json) {
  return {
    type: RECEIVE_ENTRIES,
    entries: json
  }
}

you want to write a test that verifies that the action creator returns an action that has a type property with a value of RECEIVE_ENTRIES and an entries property that contains a specific javascript object.

In order to write the test, add a file called actions.test.js next to actions.js. In actions.test.js insert:

import * as actions from './actions.js';

import {
  RECEIVE_ENTRIES,
  ADD_ENTRY,
  UPDATE_ENTRY,
  DELETE_ENTRY
} from './actions.js'

test('receiveEntriesActionCreator returns a correct action', () => {

  const entries = [{ id: '12345', password: 'abcdef' }]

  const expectedAction = {
    type: RECEIVE_ENTRIES,
    entries
  }

  expect(actions.receiveEntriesActionCreator(entries)).toEqual(expectedAction)

});

On line 10, the test() function is called given a description of what the test is trying to verify. The second parameter is the code that the test should execute. Lines 12 to 17 assemble the expected result. On line 19, expect().toEqual() is called.

In the console type npm run to start a watcher that executes the tests after you save your changes to a file that has a unit test.

Node and MongoDB with Mongoose

This post describes how to add MongoDB with Mongoose as a database to your Node application.

Interesting links

https://mongoosejs.com/
Part 3 of the Mozilla Express Tutorial
https://mongoosejs.com/docs/index.html
https://medium.freecodecamp.org/introduction-to-mongoose-for-mongodb-d2a7aa593c57
https://www.jenniferbland.com/saving-data-to-mongodb-database-from-node-js-application-tutorial/

Installing and starting MongoDB

First install MongoDB on your system. For MacOS the instructions are available on the MongoDB homepage.
brew update
brew install mongodb
The MongoDB daemon that executes the database is started with:
/usr/local/bin/mongod --config /usr/local/etc/mongod.conf

The mongo shell

The mongo shell is a command line tool that allows you to connect to the mongodb and perform queries. It will connect to mongodb://127.0.0.1:27017 if no parameters are specified

/usr/local/bin/mongo

To display the database you are using, type db
To switch databases, issue the use <db> command
To show all databases that contain at least one document, type show dbs
To show all collections in a database, type show collections

MongoDB is case sensitive! The schema passwordentry is a different schema than PasswordEntry!

Inserting:

db.PasswordEntry.insertOne( { password: "test" } )

Select all entries:

db.PasswordEntry.find ( {} )

Using MongoDB from within Node

To install the mongoose npm dependency and a JSON middleware type

npm install mongoose
npm install body-parser save

MongoDB is a NoSQL Database that deals with documents that are stored in so called collections. The synonym for a collection is a table. The synonym for a record in a table is a document.

The fields of a document are defined using a schema. Given a schema, you can create a model. A model is a factory that creates documents which then are saved into collections.

Because models can only be defined once (otherwise an exception is thrown) in the application lifecycle (You can update them several times to add more fields, but you can create them only once), you need some centralized code that defines the schema and then creates the models.

const mongoose = require('mongoose');

mongoose.Promise = global.Promise;
mongoose.connect("mongodb://localhost:27017/crypto");

// define a schema
var passwordEntrySchema = new mongoose.Schema({
  password: { type: String, required: true }
});

// this adjusts the conversion of mongoose objects to json when serializing the objects
// it outputs the _id as id and removes the _id. It also removes the __v field.s
passwordEntrySchema.set('toJSON', {
  transform: function (doc, ret, options) {
    ret.id = ret._id;
    delete ret._id;
    delete ret.__v;
  }
});

// compile the schema into a model
let collectionName = 'peCollection';

// create and export the model
// models can only be created once, that is why this code is put into its own module
module.exports = mongoose.model('PasswordEntry', passwordEntrySchema, collectionName);

Once you have that centralized module, you can import the model into other places. Here is how to create a document and save it:

var express = require('express');
var router = express.Router();

const mongoose = require('mongoose');
var PasswordEntryModel = require('../mongo/mongo.js');

router.post('/add', function (req, res, next) {

  console.log('/add ', req.body);

  var myData = new PasswordEntryModel(req.body);
  myData.save()
    .then(item => {
      res.send("item saved to database");
    })
    .catch(err => {
      res.status(400).send("unable to save to database");
    });

  console.log('/add end');
});

module.exports = router;

It is assumed, that a JSON describing a PasswordEntryModel is posted to this router.

C++ on MacOS with Eclipse CDT

The Eclipse C++ Developer Tooling adds C++ support to Eclipse.

The installation URL is https://download.eclipse.org/tools/cdt/releases/9.6/ using this URL, you can install CDT form within Eclipse using the “Install new Software” feature.

Eclipse CDT requires a C++ compiler being installed on the System. Under MacOS the easiest way to install a compiler is to install XCode from the app store. This also installs the lldb debugger which Eclipse CDT has support for. The latest version of XCode does not come with the gdb debugger which is the default debugger in a vanilla installation of CDT. That means you have to change Eclipse CDT to use the lldb debugger instead of gdb.

In order to debug using lldb, you have to edit the workspace settings and change the default debugger from gdb to lldb. The settings for the debugger are contained in Eclipse Menu > Preferences > Run/Debug > Launching > Default Launchers. In the submenu, change the Debug option to lldb and save.

React Redux Cryptofrontend

This post describes how the Cryptofrontend was created.

Description of the Crypto-Application

The cryptoapp stores password entries in a server (which for this post is assumed to be working prerequisit) and it has a frontend that displays the entries to the user. The frontend will look very similar to an email client. On the left it lists all entries. The entries in the list are only showing part of the information so the user can quickly decide which entry he wants to use. Once the user clicks one of the entries, the entire data of that entry will be displayed on the right side of the application in a details view.

Basic CRUD operations on the password entries will be possible. If the user enters the master password in the details view, the password will be decrypted and copied into the users clipboard if that is possible. Otherwise the app just displays the plaintext password for the user to copy. The decryption and encryption happens in the user’s browser. Only encrypted data is transmitted to and from the backend.

Creating the Project Structure

Update node using the node version manager (nvm) to the latest version, otherwise the later steps probably will fail. First find the latest version using nvm ls-remote. Then install that version using nvm install <version>. nvm will automatically make installed version current so it is used when executing npm and node commands.

The first step is to generate the empty project structure using create-react-app command.

npx create-rect-app cryptofrontend

Make sure that the generation did finish successfully! The generator will create a cryptofrontend folder which can be opened in Visual Studio Code. If type yarn start inside the project folder, a server will be started and the site is automatically opened in a browser.

Organizing the Code

All actions and thunk functions go into the action folder. The action folder will contain all objects that can be dispatched. A better name for the actions folder would be dispatcheables.

All reducers go into the reducers folder.

The store creation goes into the store folder.

Installing the required npm Packages

npm i cross-fetch
npm i redux
npm i react-redux
npm i redux-logger
npm i react-thunk
npm i redux-thunk

Defining the Redux State

First let’s define what state the Redux container will contain. This is an example JavaScript Object that outlines what the state comprises. There is the id of the currently selected password entry. If no entry is selected, the value will not be there at all or it will be equal to or less than zero. After the selected id, there is an array of objects, each denoting one password entry.

{
  selected_entry_id: 1,
  entries: [
    {
      id: 1,
      password: 'ad2jd92jd9dj9j9'
    },
    {
      id: 2,
      password: 'sdfsdfsfsfsdfsdf'
    }
  ]
}

Retrieving Entries from the Server

Let’s develop the application in an iterative fashion by adding little bits of functionality until the app is complete. That way the entire complexity will not hit as as hard. In a sense this allows us to apply the principle of divide and conquer.

The first iteration will retrieve entries from the server and output the entries to the developer console. The entries have to be fetched from the backend and they have to be stored in the Redux store. Normally to alter the store, an action has to be dispatched and a reducer will create the new state given the current state and the values contained in the action. In order to talk to a backend, instead of dispatching an action and defining a reducer, the thunk middleware is used which makes it possible to dispatch a function.

This function is called fetchEntries(). Once fetchEntries() did receive the entries from the server, it will dispatch an action that carries the entries retrieved from the backend. This action will be handled by a reducer that inserts the entries into the state.

Reducers

Lets first talk about the reducers. As the first iteration only cares about the entries, there is only one reducer that insert entries into the store. The root reducer will only consist of this one reducer.

import { combineReducers } from 'redux'
import {
  RECEIVE_ENTRIES
} from '../actions/actions.js'

// deals with entries
function entriesReducer(state = {}, action) {

  // switch over all action types
  switch (action.type) {

    // entries were retrieved from the backend
    case RECEIVE_ENTRIES:

      // this reducer will take the entries from the action and put copy
      // them into the store
      return Object.assign({}, state, {
        entries: action.entries
      })

    default:
      return state
  }
}

The entriesReducer only reacts to the RECEIVE_ENTRIES action and it will just copy the entries that the action contained into the store. The file also builds the root reducer:

// build the rootReducer from several partial reducers
const rootReducer = combineReducers({
  entriesReducer
});

// default export of this file
export default rootReducer;

The root reducer currently only consists of the entriesReducer because there is no other reducer right now. (A currentlySelectedEntryReducer will follow in upcoming iterations).

The next thing needed is the RECEIVE_ENTRIES action itself.

Actions, Thunks and other Dispatcheable Objects

import fetch from 'cross-fetch'

export const RECEIVE_ENTRIES = 'RECEIVE_ENTRIES'

// this function is called an action creator as it constructs
// and returns an action
function receivePostsActionCreator(json) {
  console.log('receivePostsActionCreator ', json);
  return {
    type: RECEIVE_ENTRIES,
    entries: json
  }
}

// this function is a thunk. It is dispatcheable and performs
// the server communication. Once it is done, it will dispatch
// call the action creator to dispatch the RECEIVE_ENTRIES action
export function fetchEntriesThunk() {
  console.log('fetchEntriesThunk');
  return dispatch => {
    return fetch(`http://localhost:8081/todos`)
      .then(response => response.json())
      .then(json => dispatch(receivePostsActionCreator(json)))
      .catch((error) => {
        console.log("reset client error-------", error);
      });
  }
}

This file contains one action creator and one thunk. The thunk will use the action creator to dispatch the RECEIVE_ENTRIES action once it has retrieved all entries from the backend. The entries are put into the RECEIVE_ENTRIES action by the action creator. The action is dispatched and handled by the reducer defined in the last section. The reducer will create a new state from the entries contained in the action. This is how the entries travel from the backend all the way into the store.

Store Creation

This file creates a store and adds the thunk and logger middleware:

import rootReducer from '../reducers/reducers.js';
import { createStore, applyMiddleware } from 'redux'
import thunkMiddleware from 'redux-thunk'
import { createLogger } from 'redux-logger'

const loggerMiddleware = createLogger()

function configureStore(preloadedState) {
  return createStore(
    rootReducer,
    preloadedState,
    applyMiddleware(thunkMiddleware, loggerMiddleware)
  )
}

export default configureStore;

The configureStore() function is exported. It creates the store and adds the rootReducer. It also allows to add an optional initial state, which we do not use. Also, it applies middleware. It applies the thunk middleware which allows for dispatching functions instead of only action objects. It applies a loggerMiddleware which logs every state change to the developer console.

In the app.js file, testing code is added. The testing code will also fulfill all our goals that we set for the first iteration. It creates the store, dispatches the thunk and by doing so, retrieves data from the server and inserts that data into the store.

import configureStore from './store/store.js'
import { fetchEntriesThunk } from './actions/actions.js'

// create a store
const store = configureStore();

// Log the initial state
//console.log(store.getState());
store.dispatch(fetchEntriesThunk());
//console.log(store.getState());

When you load the cryptofrontend in your browser, this code is executed and the backend is accessed. In the developer tools console of your browser, you should see all the state changes that the store is going through.

Summary for the First Iteration

Without using any components, the goal of the first iteration was to integrate the Redux Store to the backend server. There is now a thunk that GETs all entries from the backend.

Adding an Entry into the Redux Store

This thunk will POST an entry to the redux store:

export function addEntryThunkActionCreator() {

  // DEBUG
  console.log('addEntryThunkActionCreator');

  // return the thunk
  return dispatch => {
    return fetch(`http://localhost:8081/todos/add`, {
      method: 'POST',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ id: 0, password: 'Textual content' })
    })
      .then(response => response.json())
      .catch((error) => {
        console.log("POST addentry error ", error);
      });
  }
}

Note that the new entry is not added to the Redux Store, it is only posted to the backend. Given this code, the app has to dispatch the thunk that retrieves all entries to sync up its state with the backend store. An alternative would be to dispatch an action that appends the new entry to the Redux store state in the success case. This alternative saves a lot of network traffic. The following code defines an action to append a new entry to the Redux store.

Selecting an Entry in the Redux Store

The next iteration will add an action for selecting one of the entries. The idea is that after selecting an entry, the details view has to render all the entries details. The currently selected item is actually part of the state in the store. That is why the store will be extended by an action for selecting an entry. Thanks for reading and stay tuned for the next iteration.

Building the components

 

React Redux Development

For a beginner, it can be very confusing to create a React Redux app as a lot of new concept have to be understood and combined before anything sensical can be built. This post is supposed to sketch out a process for getting a React Redux app up and running in a controlled manner.

The steps are ordered from the backend towards the frontend of the application. Starting from the backend that exposes a API, the Redux model/container and then finally the React components in the frontend are created.

Creating the Backend

  1. Create the database schema in a database
  2. Create a node server using express

Creating the Redux Part

  1. Define the JavaScript Object that describes the applications state
  2. Define the actions that can be performed on the state
  3. Define the action creators that create the actions
  4. Define the reducers for the actions. The default value of the reducers state parameter defines the initial state of the Redux Container.
  5. Define the root reducer as a combinedReducer from all reducers.
  6. Define thunk reducers that retrieve data from the backend
  7. Create the container with the initial state
  8. Write a test for the entire Redux part of the application

Creating the React Part

  1. Define the components. Define what properties the components have that means, what properties the components take the data from when rendering the GUI. The properties of the component act as the interface of the component. It is the task of the React-Redux mapStateToProps Method to adapt the Redux container state to the props of the component
  2. Connect the components to Redux using Redux-React. Use mapStateToProps to map the Redux container state to the components properties.

Node and Express

Node allows you to start servers written in JavaScript. For executing the JavaScript it uses Chrome’s V8 JavaScript engine.

Express is a framework that is based on Node and allows you to easily implement an API. You can define a API using the routing features of Express. Routing is Expresses term for the definition of how a server answers web requests.

Generating a project skeleton

Express has a tool that initializes a basic project structure. First install then use that tool:

npm install express-generator -g
express --view=pug <Application Name>
cd <Application Name>
npm install

Then you can start the server.

DEBUG=<Application Name>:* npm start

You can visit http://localhost:3000/ to see the servers routing for a GET to the root URL.

Adding a router

A router defines the servers reaction to calls to a URL. A router is registered or bound to a URL in the app.js file

var todosRouter = require('./routes/todos');
app.use('/todos', todosRouter);

The code above creates a router (the router is explained later) and the binds that router to the /todos URL. All calls to http://localhost:3000/todos will now be handled by the todosRouter. 

In order to add the router itself, create a new file in the routes folder called todos.js for the todosRouter.

var express = require('express');
var router = express.Router();

router.get('/', function (req, res, next) {
  res.setHeader('Content-Type', 'application/json');
  res.send(JSON.stringify({ a: 1 }));
});

module.exports = router;

Note that this router never refers to the /todos URL! Instead it defines a routing for GET requests to / (root). There is one important thing to understand here. All URLs inside a router definition are relative.

A router does not care which URL it is bound to, instead it only defines relative URLs inside its own local context. The absolute URL of a router is constructed from appending the local URLs to the URL that the router is currently bound to.

In the context of the current example, this means that the root of the todosRouter router actually resolves to the absolute URL http://localhost:3000/todos/, because the router was bound to http://localhost:3000/todos.

Connect to An SQL Database

Install the node sql driver

npm install mssql -s
Connect to the Database in a Router (MySQL as an example)

Create a new schema:

CREATE SCHEMA `cash` ;

Create a table in the schema:

CREATE TABLE `cash`.`account_entry` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `amount` INT NULL COMMENT 'Amount in least significant currency units of the currency of the entries account. E.g. Cent for EUR if the account has EUR set as a currency.',
  PRIMARY KEY (`id`));

Define a connection settings object in one of the router files of the express project and use that connection settings object to connect to the schema using a user on the database server.

var express = require('express');
const sql = require('mssql');
var router = express.Router();

const sqlConfig = {
    user: 'root',
    password: 'test',
    server: '127.0.0.1:3306',
    database: 'cash'
}

/* GET home page. */
router.get('/', function (req, res, next) {

    const connection = sql.connect(sqlConfig, (err) => {
        if (err) {
            console.log('error');
            res.send('error');
        } else {
            res.send('DB connected');
        }
    });

    //res.render('index', { title: 'Express' });

});

module.exports = router;
Using an ORM Mapper (Sequelize)

An ORM mapper abstracts away all SQL interface code for translating between your programming language of choice and the SQL server. Instead of dealing with SQL queries, the ORM mapper lets you store and load data using objects used in your application.

When I started writing applications that used SQL databases as datastores, I wanted to write all the SQL code myself and I did not familiarize myself with ORM mappers at all. It is fun to write your own DAO and DTO class hierarchy to map from and to the SQL database but only for the first handfull of classes. As projects grow and more requirements and features and therefore objects to manage get added to the project, you quickly find yourself in a situation where you replicate your more or less dumb boilerplate code over and over for every small little insignificant new object. In reality the only thing you should care about is writing code for business logic. You should not spend time on SQL storage code if ever possible.

Another scenario is that of a high performance application. If you are required to squeeze out the last millisecond of your application, then maybe manually use SQL. In all other cases, I will recommend at least looking into the idea of using an ORM mapper. It will pay off quickly.

I really do not know which ORM mapper is suited best for your needs but as an example, lets use Sequelize. Sequelize internally connects to the SQL server, so it is possible to remove the SQL driver dependency from the example above.

Add sequelize to the project

npm install sequelize

As MySQL is beeing used in this example, install the MySQL dependencies.

npm install --save pg pg-hstore
npm install --save mysql
npm install --save mysql2

Add code to a router that inserts a new row into a table and returns the inserted element.

var express = require('express');
var Sequelize = require('sequelize');
var router = express.Router();

const sqlConfig = {
    user: 'root',
    password: 'test',
    server: '127.0.0.1:3306',
    database: 'cash'
}

var sequelize = new Sequelize(sqlConfig.database, sqlConfig.user, sqlConfig.password, {
    host: 'localhost',
    port: 3306,
    dialect: 'mysql',

    pool: {
        max: 5,
        min: 0,
        idle: 10000
    }
});

var account_entry = sequelize.define('account_entry', {
    'id': {
        type: Sequelize.INTEGER(11),
        allowNull: false,
        primaryKey: true,
        autoIncrement: true
    },
    'amount': { type: Sequelize.INTEGER }
});

autoIncrement: true,

    /* GET home page. */
    router.get('/', function (req, res, next) {

        sequelize.sync().then(function () {
            return account_entry.create({
                amount: 123
            });
        }).then(function (new_account_entry) {

            const msg = new_account_entry.get({
                plain: true
            });
            console.log(msg);
            res.send(msg);
        });

    });

module.exports = router;

Add the router to the application configuration (app.js)

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var accountEntriesRouter = require('./routes/account_entries');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/account_entries', accountEntriesRouter);

// catch 404 and forward to error handler
app.use(function (req, res, next) {
    next(createError(404));
});

// error handler
app.use(function (err, req, res, next) {
    // set locals, only providing error in development
    res.locals.message = err.message;
    res.locals.error = req.app.get('env') === 'development' ? err : {};

    // render the error page
    res.status(err.status || 500);
    res.render('error');
});

module.exports = app;

Delete the table account_entry table created manually earlier. The ORM mapper will automatically generate a table creation SQL statement from the type definition and execute that statement agains the MySQL server.

When you call http://localhost:3000/account_entries the table is created in the MySQL schema as it did not exist already and an account_entry row is inserted into the database. All that is possible without writing a single line of SQL thanks to the ORM mapper which intersects your request to store an object and does all the required SQL boilerplate for you!

 

React Redux Fetch Data from an API with Redux Thunk

The GUI of a webapp oftentimes has to retrieve its data from a backend system. In this post we assume that the backend system is providing the data via an API that supports GET requests. This post rehashes the current best practices for calling a backend API and retrieving the data as described in the Redux Advanced Tutorial.

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