Integrating Navigator.onLine into React-Redux

Recently I have been working on an React-Redux web application with a requirement that it still worked offline. This is the first part in a series of blogs on what I've encountered. I will also assuming that you're already comfortable with creating a React-Redux application.

Capturing Online/Offline event

Most browsers now support the navigator.onLine property but you can check here.

To capture the onLine status we first have to create a listener for the online and offline events using window.addEventListener. In the listener we will pass the event to listen for and a function (handler).

window.addEventListener(name, e => {
    console.log(navigator.onLine);
});

In the handler we then have access to navigator.onLine but this isn't currently in the redux ecosystem which is the end goal so that we can then react to that change.

Adding Middleware

To integrate this functionality into Redux I'll be using redux-thunk so that we can use functions instead of action creators. The functions will dispatch the action when our app is either online or offline. To enable middleware in redux we'll use:

import { createStore, applyMiddleware } from 'redux'
const createStoreWithMiddleware = applyMiddleware(reduxThunk)(createStore);

Then we can create our store with middleware:

const store = createStoreWithMiddleware(reducers);
Adding Listeners to Dispatch

We'll wrap the window.addEventListener in a function which will return a dispatch function.

function listenToWindowEvent(name, mapEventToAction) {
  return function (dispatch) {
    function handleEvent(e) {
      dispatch(mapEventToAction(e));
    }
    window.addEventListener(name, handleEvent);
  }
}

Here we have a function which takes the name of the event to listen to and a named function to dispatch the action.

function navigatorOnLine(e) {
  return {
    type: 'WEB_APP_ONLINE',
    payload: navigator.onLine
  };
}

When navigatorOnLine is triggered an action is returned with a type and the navigator.onLine value.

Now finally to connect this up we'll use our store to create the listeners.

store.dispatch(listenToWindowEvent('load', navigatorOnLine));

store.dispatch(listenToWindowEvent('offline', navigatorOnLine));

store.dispatch(listenToWindowEvent('online', navigatorOnLine));

To get an initial value of we're on or offline the load event is first listened to.