Install and Use Reactotron for Debugging

Author

Spencer Carli

Developer, cat dad, and devout pizza lover. Teaching at React Native School and building apps with Handlebar Labs.

Last Updated: June 12, 2019

Before anything else we need an app to debug. I'll be using my weather example from React Native by Example. The code exists on Github with the complete app being in the finished branch.

Why Reactotron?

If you've ever worked with me you know I'm a fan of old school debugging - it's all I've ever known. I'm going to use the React Native Debugger and a boatload of console.log until I fix the problem.

This can be a pain, it can be intensive, and it can clutter up your project.

That's where a tool like Reactotron comes in. It's a cross platform app that allows you to track a variety of things in your application automatically. Today we'll be scratching the surface by looking at how we can use it to track our remote requests and AsyncStorage usage.

Installation

First, install the correct desktop app for your platform from the releases page.

We'll then add the project as a development dependency to our React Native project.

yarn add --dev reactotron-react-native

Finally, we configure it. First create a config file for Reactotron.

App/config/ReactotronConfig.js

import Reactotron from 'reactotron-react-native';

Reactotron.configure().useReactNative().connect();

and then import it, if in development, from your main app file.

App/index.js

// ...

if (__DEV__) {
  import('./config/ReactotronConfig').then(() =>
    console.log('Reactotron Configured')
  );
}

// ...

Monitoring Network Requests

Right out of the gate you get network monitoring. To me this is fantastic because it's something I'm constantly working with and constantly debugging. Let's take a look...

01

You can see that, in the timeline tab, we can see a timeline of everything our app does and associated information. Digging into one of my API requests we can further view what data was sent in the request, what the response was, the headers, etc. All valuable information.

For me this is highly valuable because it's very likely I made some query typo that I've overlooked. Or maybe I'm missing a required header.

I can also go ahead and copy the response to further analyze it.

Monitoring AsyncStorage

Just like network requests we can automatically monitor AsyncStorage via Reactotron. Being able to view when the call is happening, what key you're writing to, and what you're writing are all invaluable.

02

For example: on a recent project I would grab some data from AsyncStorage to populate a screen. Due to the way I was developing the feature I always had data in the key I was accessing but in the real world a user wouldn't yet have data in AsyncStorage before I grabbed the data meaning I had to initialize an empty array. This would have been much easier if I had enabled Reactotron and looked that, in fact, there was no data that existed when I made my AsyncStorage.getItem call.

Next Level Logging

Everything we've done so far has been automatic. What if we want to manually log things? Let's take this example:

When I make a network request that throws an error I want to log to that something like Sentry in production. If that happens in development though I want to see that displayed in Reactotron.

To do this, I'll create an Analytics.js file in my util directory. I can then use Reactotron.log to transfer that message to Reactotron.

Analytics.js

import Reactotron from 'reactotron-react-native';

export const logError = (error) => {
  if (__DEV__) {
    Reactotron.log(error);
  } else {
    // Log to your production error monitor
  }
};

I can then capture errors for every network error I encounter by catching that from my weatherApi.

App/util/weatherApi.js

import { logError } from './Analytics';

const apiKey = '1648e403f1e44103b747e25c55f8c2fb';

export const weatherApi = (path, { zipcode, coords }) => {
  // ...

  return fetch(
    `https://api.openweathermap.org/data/2.5${path}?appid=${apiKey}&units=imperial&${suffix}`
  )
    .then((response) => response.json())
    .catch((error) => {
      logError(error);
      throw new Error(error);
    });
};

Now whenever an error occurs with my fetch request I'll see it in Reactotron with whatever information I need.

Sure, this is basically just a glorified console.log but it's allowing us to do all of our debugging work in a single utility that is easily filterable.

We can also make better looking messages, like so:

Analytics.js

import Reactotron from 'reactotron-react-native';

export const logError = (error) => {
  if (__DEV__) {
    Reactotron.display({
      name: 'ERROR',
      preview: error.name,
      value: error.message,
      important: true,
    });
  } else {
    // Log to your production error monitor
  }
};

03

Custom Commands

The final thing I want to share is custom commands. Honestly, until writing this article, I didn't know this existed. But now I can't wait to bring this into my normal workflow.

Custom commands allow you to register commands from your code in the full context of React Native and then, at the press of a button, run that command.

A perfect example? Nuking your entire AsyncStorage cache. I write a lot of apps that store a lot of data in AsyncStorage and typically my solution is to either clear everything out the next time the app refreshes (meaning I have to write and then delete code) or I just delete the app from the device and re-install it.

Now, I can register a custom command in Reactotron to do that at a moments notice. I'm super excited about this.

ReactotronConfig.js

// ...

Reactotron.onCustomCommand({
  command: 'Clear AsyncStorage',
  handler: () => {
    AsyncStorage.getAllKeys()
      .then((keys) => AsyncStorage.multiRemove(keys))
      .then(() => {
        alert('AsyncStorage cleared.');
      });
  },

  title: 'Clear AsyncStorage',
  description: 'Clears all data from AsyncStorage.',
});

All I do is register a command, a chandler, and some additional optional info and I'm on my way to nuking all the data in my app.

04


And that's all for today. I'm excited to start integrating Reactotron into my development workflow.

Links

React Native School Logo

React Native School

Want to further level up as a React Native developer? Join React Native School! You'll get access to all of our classes and our private Slack community.