How to monitor network changes using Redux Saga in React Native

January 01, 2019

What is an Event Channel?

Redux Saga consists of eventChannels to communicate between external events and sagas as a factory function. The events are from the event sources _other than the redux store.

Here’s a basic example from the docs:

  import { eventChannel, END } from 'redux-saga'
  
  function countdown(secs) {
    return eventChannel(emitter => {
        const iv = setInterval(() => {
          secs -= 1
          if (secs > 0) {
            emitter(secs)
          } else {
            // this causes the channel to close
            emitter(END)
          }
        }, 1000);
        // The subscriber must return an unsubscribe function
        return () => {
          clearInterval(iv)
        }
      }
    )
  }

Things to note:

  • The first argument of the eventChannel is a listener function.
  • The return method is the unregister listener function.

Emitter initializes the listener once after which all the events from the listener are passed to the emitter function by invoking it.

How should I hook up Redux Saga’s Event Channel with React Native’s Network(NetInfo) API?

The React Native’s NetInfo isConnected API asynchronously fetches a boolean which determines whether the device is online or offline.

Dive into the code

First, we need to create a start channel method.

  function * startChannel(syncActionName) {
    const channel = eventChannel(listener => {
      const handleConnectivityChange = (isConnected) => {
        listener(isConnected);
      }
  
      NetInfo.isConnected.addEventListener("connectionChange", handleConnectivityChange);
      return () => NetInfo.isConnected.removeEventListener("connectionChange", handleConnectivityChange);
    });
  }

The next step is to listen for the event changes within the channel.

  while (true) {
      const connectionInfo = yield take(channel);
    }

The final step is to pass a custom action to the channel so that the value can be synced using your action.

  while (true) {
      const connectionInfo = yield take(channel);
      yield put({type: syncActionName, status: connectionInfo }); // blocking action
    }

This channel can be used in our default exported generator by using the call operation.

  export default function* netInfoSaga(options = {}) {
    try {
      yield call(startChannel, options.syncAction);
    } catch (e) {
      console.log(e);
    }
  }

The exported generator can then be imported and used as a detached task using spawn/fork operation in our main saga.

Usage

The above code has added it as a package react-native-network-status-saga to include some of the more useful and cool parameters.

Here are the links

Join My Newsletter

If you've found any of my articles useful, subscribe to receive more quality articles straight to your inbox.

I won't send you spam and you can unsubscribe at any time


Personal Blog by Pritish Vaidya

Working on solving some interesting problems

© 2021, Pritish Vaidya