React Native Flipper: A Better Way of Debugging
Tags: reactnative, flipper, debugging
Published: 2020-12-15 14:24:01

<!-- wp:heading -->
<h2>What is Flipper?</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>It's an open-source debugging tool made by Facebook for <a href="https://pagepro.co/mobile-app-development.html" target="_blank" rel="noreferrer noopener">mobile apps</a> – both for iOS and Android. It existed for quite some time, but it has not been widely used. However, it can change with the release of <a href="https://pagepro.co/react-native-development.html" target="_blank" rel="noreferrer noopener">React Native</a> 0.62, which has Flipper integrated by default.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Flipper is using <strong>remote debugging,</strong> which lets the app run in the environment as close to production one as possible. It gives you more confidence when debugging apps in comparison to <strong>direct debugging</strong>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>But the biggest advantage of Flipper which differs it from other debugging tools is plugin library that allows you to install plugins directly from Flipper interface and extend its capabilities. You can also make your plugins and share them! But let's go from the start.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>Direct vs Remote Debugging</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>You may be wondering: "What is remote or direct debugging?" or "Why do I want to use Remote Debugging at all?". Let me explain. :)<br></p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":4523,"sizeSlug":"large"} -->
<figure class="wp-block-image size-large"><img src="https://pagepro.co/blog/wp-content/uploads/2020/10/image.png" alt="Difference between Direct and Remote Debugging" class="wp-image-4523"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>By default, when React Native app runs on the target device, it uses javascript core as its engine. Things look different when you start debugging your app, for example, using web remote debugging or React Native Debugger. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>In this case, the app is running on your local machine using V8 underneath. It is an issue because it can lead to errors which may be missed just because they don't appear on V8 or vice versa. Also, the performance of your app is different when running on your machine versus a real device.</p>
<!-- /wp:paragraph -->

<!-- wp:code-mind/cta {"title":"Want To Build A Commercial App in React Native?","buttonTitle":"Get a FREE Consultation Call To Set Up The Fundamentals","buttonUrl":"https://pagepro.co/hire-react-native-developers.html"} -->
<div class="wp-block-code-mind-cta c-cta-block" style="background-color:;color:"><div class="c-cta-block__content"><p>Want To Build A Commercial App in React Native?</p><div><a href="https://pagepro.co/hire-react-native-developers.html" style="color:;border-color:" class="c-cta-block__button theme-bg-3">Get a FREE Consultation Call To Set Up The Fundamentals</a></div></div></div>
<!-- /wp:code-mind/cta -->

<!-- wp:heading -->
<h2>How to start using Flipper</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>As I mentioned at the beginning, if your app is using React Native 0.62+, you already have Flipper integration in your app. Just install <a href="https://fbflipper.com/">Flipper</a>, and you are good to go!.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>If you are using older versions, there are some additional steps to make Flipper work with your app. Follow these URLs for both <a rel="noreferrer noopener" target="_blank" href="https://fbflipper.com/docs/getting-started/ios-native">iOS</a> and <a rel="noreferrer noopener" target="_blank" href="https://fbflipper.com/docs/getting-started/android-native">Android</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>First steps</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>This is what you will see after starting Flipper (assuming you are running a React Native app on your machine or connected device).</p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":4526,"sizeSlug":"large"} -->
<figure class="wp-block-image size-large"><img src="https://pagepro.co/blog/wp-content/uploads/2020/10/image-2-1024x610.png" alt="Flipper main window" class="wp-image-4526"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>From here you can access things like:</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li><strong>Crash Reporter</strong> – Logs from crashes</li><li><strong>Logs</strong> (which consist of logs from js and native logs without the need to launch Xcode or Android Studio)</li><li><strong>Layout</strong> – the equivalent of Elements browser from Chrome debug console</li><li><strong>Network</strong> – lets you browse all your incoming/outgoing network requests</li><li><strong>Shared Preferences Viewer</strong> – this lets you view and edit shared preferences</li><li><strong>Hermes Debugger</strong> – debugger for Android apps using Hermes</li><li><strong>React DevTools</strong> – whole React DevTools as a plugin inside Flipper</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>If you want you can install many other plugins that you might need using plugins manager, it allows you to browse your installed plugins, removing them updating or adding new ones.</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center","id":4527,"width":580,"height":345,"sizeSlug":"large"} -->
<div class="wp-block-image"><figure class="aligncenter size-large is-resized"><img src="https://pagepro.co/blog/wp-content/uploads/2020/10/image-3.png" alt="Flipper plugin manager" class="wp-image-4527" width="580" height="345"/></figure></div>
<!-- /wp:image -->

<!-- wp:heading -->
<h2>Writing your own plugins</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Using Flipper, you can make your plugins to help you debug/test specific use cases in your app. You can make any interaction with your app - exchanging data, sending or receiving events and wrap it with helpful UI.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Flipper plugin consists of two main parts:</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li><strong>Mobile Client</strong> – which is the code running on a target device</li><li><strong>Desktop App</strong> – which is an Electron App running on your machine</li></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3>Desktop App</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>To start writing plugins for Flipper, you need to install <strong>flipper-pkg </strong>either using yarn or npm. Then you can create plugins using <strong>flipper-pkg init</strong>.<br>You will be asked for id and title of your plugin.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Then replace the code in <strong>index.tsx</strong> of your plugin with the code below:</p>
<!-- /wp:paragraph -->

<!-- wp:code-mind/code {"code":"import {\n  Text,\n  Panel,\n  ManagedDataInspector,\n  createTablePlugin,\n  TableBodyRow,\n} from 'flipper';\nimport React from 'react';\n\ntype Row = {\n  id: string;\n  title: string;\n};\n\nconst columns = {\n  title: {\n    value: 'Title',\n  },\n};\n\nconst columnSizes = {\n  title: 'flex',\n};\n\nfunction renderSidebar(row: Row) {\n  return (\n    \u003cPanel floating={false} heading={'Info'}\u003e\n      \u003cManagedDataInspector data={row} expandRoot={true} /\u003e\n    \u003c/Panel\u003e\n  );\n}\n\nfunction buildRow(row: Row): TableBodyRow {\n  return {\n    columns: {\n      title: {\n        value: \u003cText\u003e{row.title}\u003c/Text\u003e,\n      },\n    },\n    key: row.id,\n    copyText: JSON.stringify(row),\n    filterValue: `${row.title}`,\n  };\n}\n\nexport default createTablePlugin\u003cRow\u003e({\n  method: 'testMethod',\n  columns,\n  columnSizes,\n  renderSidebar,\n  buildRow,\n});\n"} -->
<pre class="wp-block-code-mind-code c-code"><code class="javascript">import {
  Text,
  Panel,
  ManagedDataInspector,
  createTablePlugin,
  TableBodyRow,
} from 'flipper';
import React from 'react';

type Row = {
  id: string;
  title: string;
};

const columns = {
  title: {
    value: 'Title',
  },
};

const columnSizes = {
  title: 'flex',
};

function renderSidebar(row: Row) {
  return (
    &lt;Panel floating={false} heading={'Info'}>
      &lt;ManagedDataInspector data={row} expandRoot={true} />
    &lt;/Panel>
  );
}

function buildRow(row: Row): TableBodyRow {
  return {
    columns: {
      title: {
        value: &lt;Text>{row.title}&lt;/Text>,
      },
    },
    key: row.id,
    copyText: JSON.stringify(row),
    filterValue: `${row.title}`,
  };
}

export default createTablePlugin&lt;Row>({
  method: 'testMethod',
  columns,
  columnSizes,
  renderSidebar,
  buildRow,
});
</code></pre>
<!-- /wp:code-mind/code -->

<!-- wp:paragraph -->
<p>Let me explain what's happening here. We are using builtin Flipper method <strong>createTablePlugin</strong> which allows creating native-looking tables just like <strong>Logs</strong> of <strong>Network</strong> plugins have.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Using <strong>Row</strong> we define what data we have in each row of our table. Next <strong>columns</strong> and <strong>columnSizes</strong> define our column names and their width. Then we have two methods. <strong>buildRow</strong> as name suggests tells Flipper how we want to fill our row with data and for example how to handle copying. <strong>renderSidebar</strong> fills sidebar with data from row.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The last step is to export our plugin filling it with our configuration and <strong>method</strong> field, which tells on which method name it should react. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>After we are done we can use <strong>yarn lint </strong>or<strong> npm run lint</strong> to check if our app doesn't have any errors and then <strong>flipper-pkg pack &lt;plugin-directory&gt; -o &lt;output-directory&gt;</strong> to create a bundle of our app which then can be installed in flipper. We can install it later using plugins manager by dragging our bundle onto it.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Mobile Client</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Although Flipper allows writing native clients for Android and iOS, we will focus now only on React Native ones.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>First, we have to add <strong>react-native-flipper</strong> plugin to our app using yarn or npm. For a simple test of the plugin, you can add this code to your app.</p>
<!-- /wp:paragraph -->

<!-- wp:code-mind/code {"code":"import {addPlugin} from 'react-native-flipper';\n\n  const arr = [\n    {id: '0', title: 'test1'},\n    {id: '1', title: 'test2'},\n  ];\n\n  addPlugin({\n    getId() {\n      return 'test';\n    },\n    onConnect(connection) {\n      arr.forEach((item) =\u003e {\n        connection.send('testMethod', item);\n      });\n    },\n    onDisconnect() {},\n  });"} -->
<pre class="wp-block-code-mind-code c-code"><code class="javascript">import {addPlugin} from 'react-native-flipper';

  const arr = [
    {id: '0', title: 'test1'},
    {id: '1', title: 'test2'},
  ];

  addPlugin({
    getId() {
      return 'test';
    },
    onConnect(connection) {
      arr.forEach((item) => {
        connection.send('testMethod', item);
      });
    },
    onDisconnect() {},
  });</code></pre>
<!-- /wp:code-mind/code -->

<!-- wp:paragraph -->
<p>This code will send two simple messages to our desktop plugin. First, we import the <strong>addPlugin</strong> method, which allows us to register our client. Add plugin should at least implement <strong>getId</strong> method which identifies our client and should return the same id you have defined when creating your desktop app so they could identify each other.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Then there are <strong>onConnect</strong> and <strong>onDisconnect</strong>. They are triggered when our app connects or disconnects from desktop app respectively. <strong>onConnect</strong> has <strong>connection</strong> which we will use to send or receive events to/from our app. Here using <strong>send</strong> method we first provide name of our method which we defined earlier while we were exporting our desktop app in this case it is <strong>testMethod</strong> and next we provide an object with the data we want to send.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Result</h3>
<!-- /wp:heading -->

<!-- wp:image {"id":4531,"sizeSlug":"large"} -->
<figure class="wp-block-image size-large"><img src="https://pagepro.co/blog/wp-content/uploads/2020/10/image-4-1024x607.png" alt="Our working flipper plugin" class="wp-image-4531"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>After all of this is done we should see our plugin in Flipper, after enabling it you should see two entries in the table and when you click on one of them a sidebar with details of the sent object should appear.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>Final thoughts</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Using Flipper makes <a href="https://pagepro.co/mobile-app-development.html" target="_blank" rel="noreferrer noopener">mobile app development</a> easier because of all its features. Flipper consists of many tools that are essential for debugging apps like logs, network and dev tools. But also it can be extended with other plugins which give it limitless possibilities to fit in any complex use case where other tools may not be enough. Also, Remote debugging is a nice addition here, making us closer to a real production-ready app while we test our apps.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>This guide was made based on my own experience and whatever i could find on <a href="https://fbflipper.com/docs/extending/js-setup" target="_blank" rel="noreferrer noopener">Flipper Docs</a>. If you want to find more in-depth info about creating flipper plugins please check there.</p>
<!-- /wp:paragraph -->