Video details

Chain React 2018: Debugging and Beyond with Reactotron by Darin Wilson


If you've spent any time with React Native, you've probably tried debugging your apps with Chrome. It's handy, it's familiar, it kinda works, but maybe you've thought "this could be better." And you're right: it can be. In this talk, you'll meet Reactotron, a free, open-source development tool for your React and React Native projects. You'll see how just a few lines of code will give you access to a world of useful information about what's going in your app. Get better stack traces on errors, peer into the gory details of your network requests, pry open your async storage, subscribe to Redux store changes, debug your sagas, and the list goes on. By the end, you'll be ready to start working with Reactotron in your own projects, and wonder how you ever worked without it.


Good morning. Thanks for coming to the talk today. Get it's a single track conference. There isn't really anywhere else to go right now, but you chose here instead of the hallway. And I appreciate that. Debugging and beyond with React to Tron let's start by talking about developer experience. So these days we have a lot of choices when it comes to the platforms and technologies we use to build our apps. And one of the things we consider when we make those choices is developer experience. It's no longer just a matter of how fast is it, how stable is it? How many times did I read it about it on Hacker News this week? What is the development experience like? What's the tooling like? What's the environment like? Am I going to feel like this platform is working with me or against me? And one of the reasons so many of us got excited about React Native when it first hit the scene is it had a lot to offer in terms of development experience. For one thing, we got to bring our own editor. It used to be if you were doing native app development, you had to use Xcode for iOS, Android Studio, or even Eclipse for Android. Now, some people love Ides and some people curse their very names. But the point is, you didn't have a choice. You're stuck with it. React Native came along and said, well, guess what? You can now do apps with a real native look and feel and use whichever editor strikes your fancy. Hey, it's good in the pinch. React Native also gave us live reload. Now, for those of you who weren't around to experience app development before Live Reload, ask your grandparents. It was not fun. Compile times were slow, sometimes very slow, and it was a real drag to have to wait tens of seconds or even minutes for a large application just to see what happened when you moved a button two pixels over to the right with Live Reload, we got to see the results immediately. And it was a huge gain. React Native also gave us a debugger. This was perhaps not as huge a win in the form of Chrome. Now, don't get me wrong, it was great to have a debugger. And for those of us who had been doing web development, it certainly felt familiar. But there are some issues were and are some issues debugging with Chrome? For one thing, you're not running in the exact same environment. Very little secret here. By default, React Native uses the JavaScript core engine to execute your app code. That's how it runs in production. That's how it runs when you're developing normally, when you start debugging, your code actually executes within Chrome. Chrome does not use the JavaScript core engine. Chrome uses V Eight, which is a completely different environment. Now, they're pretty close. A lot of times you don't know the difference. But even React Natives documentation says while both environments are very similar. You may end up hitting some inconsistencies. I think it would based on our experience. Anyway, it would be more accurate to say if you do this long enough, you will hit some inconsistencies. And anybody who's been doing this for a little while has some story to tell you about the error that didn't get thrown in Chrome, but did get thrown in their production app, or worse, vice versa. So this is a little bit of a problem. The other issue is that debugging kind of interrupts your workflow. Now think about how this works. You're just coding away and you're working on your awesome app as you do, and you're clicking around, testing all the different features, and then suddenly the old red screen of Doom. Now sometimes you can just look at the top of the stack, trace and go, oh yeah, that was stupid. I know what that is. But sometimes the problem is a little more subtle and you have to figure it out. So now you're making a decision. All right, what do I need to do? Do I need to set a Breakpoint somewhere? Will a good old fashioned console log do the trick? And if so, where do I place it? Then you need to restart your app in debug mode, get yourself back to where you were, and hope that you can recreate the problem. This is not exactly ideal. So one of our engineers at Infinite Red, Steve Kellock, was thinking about this, and he asked me to point out this is an actual picture of him, and he thought, okay, we're React native developers. We care about developer experience. I think we can do better. And so he started working on a tool, and over the last couple of years, folks inside and outside of Infinite Red have been contributing to it. We are just I found out this morning about to release version two, and that tool is called Reactatron. Thank you. Steve's mother is here. Apparently. What is Reactatron? Well, Reactatron is not really a debugger in the traditional sense, and it is certainly not a drop in replacement for Chrome. What it is is a tool that gives you insight into what's going on inside your app while it's running. So if an error happens, you can not only see the error and what it was, but the steps that were leading up to it. So while it doesn't necessarily replace Chrome as a debugger, it can certainly greatly reduce the need for it, or perhaps even eliminate it altogether. So how does it work? Well, there's kind of two parts to React to, Tron. The first part are a series of libraries that you install into your app as dependencies, same as any other. We recommend running them as development dependencies only. You don't really want this stuff running in production. And when those libraries are activated, they get all up into your application's business and they start monitoring everything API requests any errors that start happening, changes to the store, actions, any of that stuff. And as these events happen, it shoots data across these events to the second part of Reactatron, which is the desktop app. This is kind of Reactatron proper, and the desktop app takes all this data, formulates it into a nice format, and displays it as a timeline. So in this way, Reactatron is sort of like a Twitter account for your app. As things are happening, Reactatron is posting for you and putting it all in it to a timeline that you can go back and look at when you need to. Now, just like a regular Twitter account, not every single bit of data is relevant or useful all of the time, but at least the information is there when you need it, and you need to look back and see what went wrong. So based on all this, if you've been keeping track of what Facebook is doing, you might be thinking, okay, but what about Sonar? This sounds an awful lot like Sonar. So a few weeks ago, Facebook announced that they were open sourcing, a tool they were working on for a long time that indeed has libraries that sit in your app and sends them across via WebSockets to a desktop application and produces a nice timeline for you. Now, right now, at this moment, Sonar only works for a native development. React native support will be coming along at some point, we don't really know, but it naturally begs the question, why would we build something that was pretty close to what Facebook was doing? And the answer is we didn't know. But like I said, right now, as far as I know, you can't even use Sonar with React native. It's really meant for native development. We don't know where it's going, we don't know where it's headed, but we know that right now. Today, in this moment, React to Tron has quite a bit to offer React native developers. We use it a lot in house for our stuff, so we're going to keep rolling with it for the time being. Setting up for React to Tron doesn't take much code. Just somewhere in your startup, you need to do this, import React to Tron and then make a configure call. You can pass in a bunch of different parameters there. That one is not even required, but the documentation explains it. And then we recommend you start with this call. Use React native. Reactatron uses a plug in architecture. All of its features are implemented as discrete plugins, and you can mix and match those use some, don't use, some however you like. But this call use React native is sort of like a preset that gives you a bunch of the best plugins that we found the most useful for React native development. All right, let's see how this looks like in action. So I've created a little demo app over here. This is pretty simple. It connects to the Music Brains service. And Music Brains is an open source database that has information about bands, artists, recordings, albums, all that kind of stuff. And they've got a public API. So this app lets you search for an artist and you can see information about the artist and the albums they've recorded. And if you like a different particular artist, you can save it into your favorites. Not much more beyond that. And over here on the left, we have Reactatron, and it's already configured to use Reactatron, and the app just started up. So Reactatron is not telling us very much at this point, but it's telling us that we've made a connection. And if I open it up, I can see information about the device that's connected, what platform, what version sizes, and all that kind of stuff down at the bottom. I hope you can see that. Yeah, there it is. It tells us that there's one connection. You can have multiple devices connected to a single instance of Reactatron that can be Android, iOS, whatever. And if there were more than one device connected here, they would be showing up here and I could switch between them. The timeline will only show one device at once. So you don't get intermixed from a bunch of different devices, but you can switch between them. For now, we'll just stick with this one. So now what you do is just go into your app, start clicking around, see what's happening. We're going to run a search here. And there's our first red screen. So now, as you can see, Reactors Run is starting to fill up with information. The timeline is in reverse chronological order. So we can start at the bottom and work our way up and see what happened. So here's the connection we saw at the very beginning. Then we see that an API request happened. So we can look at the URL, we can see the status code of the response. We can look at the raw response and see what we got back. We got some results. This all looks good. We can look at the response headers and we can look at the request that has been sent out. So everything related to the request and the response is right here for us to look at. We can also see that we made a call to Async storage. So the app saves your searches to Async storage. So they're there for you later. And if we open it up, we can see that we set the key MBB searches, Music Brains browser. And these are the searches we have saved here so far, so good. Now we get to our errors. There's two errors here. I'll explain why a little bit later. But here's the critical one right now, the reference error that says can't find variable artist. So if I pop it open first, I see the same stack trace that we got in the red green. But if we scroll down, we get some more useful information. First we get the line of source code that shows us exactly where the error happened, plus the lines of code around it so we can see it in context. And then below that we've got a more detailed Stack trace. This not only shows us the file and the line number that we got in the red screen, but also tells us the function that was executing at that point in the trace that can help you get oriented. Now you also notice that a bunch of lines in the Stack trace are grayed out. So the grayed out portion are the elements of the trace that are outside of your own application code. So this is stuff in your dependencies or in React native itself. In other words, it's probably not where your problem lies. As much as we like to blame other people for our errors, it's usually our own damn fault. And so the Stack traces that come from our code are highlighted so we can take a look at them. So looking at this in context, I can see what the problem is. When we kicked off Map, we created the variable called Artist rather than artist so we can fix that. I've set up the React Editor environment variable so I can just click on this line and my editor will pop to the exact problem. I can hit save and we'll try this again. We'll search for the police and now we're back in business. So notice the difference in workflow there compared to using Chrome. I was just using my app formally in the regular runtime environment and I got an error. Instead of trying to figure out how to define that error, I just flip over to React to Tron where the information is there waiting for me and I don't have to retool my code to figure it out. Now sometimes you do want to send a message and have it appear in Reactron and that's supported. So over here I've got a call to React to Tron log. React to Tron. Log works exactly like Console dot log. Exact same API, but instead the results will show up in React to Tron. That error is coming later. And see, I said hello, chain react here. That's what I said over here. Now for convenience, we here at Infinite Red like to do a cute little hack where we assign React to Tron to Console Tron. So we assign it to the global Console object. That means we can access it anywhere without having to do an import. It's just a shortcut. So this call here could actually be written like this and I'll get the same result. Not that one. Oh, Console log, that won't work. Console Tron, you all are better than a compiler. There we go. Same thing. Now if you want to make your message stand out, you can, you can call log important. I'm going to spell it right this time. And this time it'll have a little highlight attached to it so that can make it stand out if you've got some other errors going on. And if you really want to get fancy, there is the display function. So I'm going to comment this out. And this has a whole bunch of different options you can pass in to control how your entry looks. So name is what will show up here in the Orange. Important decides whether it's going to have that highlight or not. Preview is a little text that will show up here before you open it up. Value is the value we'll see when you do open it up and we're passing in an object. An image is. Well, it's an image. So if we save that refresh again, here's our oh, Hi. And here's our preview text. Here's the value we sent. And there's a picture of a cat. So you can see how this might be useful. If you were talking to an API that was returning image URLs and you wanted to look at the raw data, you could, but really it's for cats. So this covers some of the basics that we got out of the box with that use React native call, but of course important part of debugging and figuring out where the problems are our state management. And so we're going to add a couple of other plugins to our Reactron config. This app uses Redux and Sagas. So I'm going to change the Reactatron config to turn on the Redux plugin and the Saga plugin. So now I'm telling React to Tron. Hey, guess what? My app uses Redux and Sagas. Please give me information about that as well. So now when we restart the application, I've got information about Sagas and actions going through. And as I go through and start executing stuff, I'm starting to get a lot more data. Now if you open up one of these actions, it will tell you exactly what the parameters of that action were everything that went into that call. So we see that it is type search artist request and we see the query string as well. If I click this little repeat button, I can actually fire off the action again from Reactatron in the app. So if I click this, it's going to redo the search. It did it pretty fast and if I click this button I can actually edit the details of the action before I fire it. So in this case I did a search for the police. Let's change that to the Beatles. And now my search results reflect the Beatles. But you can actually edit anything about this, including the type if you want to. So I could even change this to navigation back and it goes to the back. And I could even add parameters if I want to react to. Tron understands how Sagas work. So if we open one of these Sagas. We can see every step of the saga that got executed along with a little mini. Not super precise, but gives you a general idea benchmark. And it's awareness of Saga is super helpful when you run into errors. So if you've ever done Sagas before, you're probably familiar with this nice little thing. I don't know if you can read it, but it says uncaught at root. And basically this is the system saying, hey, guess what, something wrong deep in the recesses of one of your sagas. Good luck finding it. Get back to us later. They will always look like this if you have an error in Saga. But if we look at the timeline, we can see the uncaught at root error here. But if we look a little further, there's another error. This is the underlying error that caused the uncaughted root error to get thrown in the first place. In other words, this one is where your real problem is. So if we pop that open, we can see that I used Snake case where I should have used Camel case. So again, we'll click over, fix that reload. And now we've got some information about John Coultering. So that's the basics of what you get in the timeline. But keeping track of the store in your application is also useful. And React to Tron has some tricks for that. There's a tab here that says State, and there's two tools we can use here. One is called Subscriptions, and this allows you to monitor changes to your store as they happen. So I'm going to open this up and create a new subscription. Now, in this app, I've got an item in my store at the top called Artists. And within that object, I've got another object called Results. This is where I store the search results. When I've gotten them back from Music Brains, they go into the store. So when I create this subscription, I'm saying, okay, Reactatron, I want you to keep an eye on the store, and in particular, look at the artist results value. And anytime that value changes, I want you to let me know about it. So that's great for the setup. We switch back to the timeline and let's go back to Search. We search for the police, and now we see this line that says Subscriptions. One changed because the results updated. And if I open it up, I can see what that value is now after the change. So if I do a new search, do this, I get another subscription change noticed and the new results are there. So this is super handy if you've ever been working through your app and you're like, hey, wait a minute, who changed this in the store? It was probably you somewhere. But you can set up a subscription, start clicking around and figure out exactly where that is. Now, as you can see, the timeline is starting to fill up. And if you want to focus on what you're looking at. Like, if you're really just interested in subscriptions, we can click on this filter, Uncheck everything, say we just want the subscriptions for now, and then that's all we see. Another tool we've got in the State tab here is for Snapshots. So I've got them in the state now where I'm on the search results screen and I've got a nice list of results. I'm going to take a snapshot of that. And by default it gives me the timestamp, but I can change it. So I'm going to say search results. And what just happened is React went into the app and it grabbed the entire store, the whole kit and caboodle, and brought it into React to Tron and started keeping track of it locally. Now, I could go to another part of my app will say the Favorites. I'm going to take another snapshot here. We'll call this Favorites. And now I've got this state saved. Now, at this point, I can click on any of my saved States and React to Tron will take that whole store and push it back onto my app. And it'll be just as though I'd gotten there, naturally. So if I click on search results, I'm back on the search results screen. If I click on Favorites, I'm back to Favorites. So this is sort of a more deliberate form of time travel. Instead of grabbing every single snapshot, every time something changes and you get a big list of these things, you can be very specific and say, all right, I just want this one. I just want this one and go back and forth as you need to. And this is a good example of how Reactatron can not only get data from the app, but actually control the app a little bit. And one kind of new feature along those lines we just put in pretty recently is something we call custom commands. And Custom commands allow you to automate certain parts of your development workflow in the app. So think about this search feature. If I was trying to track down a problem in here, I need to get to the search screen and maybe I need to change the data here a little bit. Click Search, see the results. If I was debugging something in here and I was doing that over and over again, it would get pretty tedious pretty fast. But all of that is scriptable. It's just since I'm using Redux, it's just a matter of firing off the right actions and custom commands. Let me do that. So the way to set up a custom command, you go into your code and you call console. Tron on Custom command and give it the string you want to use. I'm going to use Search in this case and then a function. And in this function, I fire off the actions necessary to start a search. So what I'm saying in effect here is, all right, when Reactitron sends this command to my code, I want to execute this function and do this search and the way to kick that off, I go back to React to Tron, pop open the custom command dialog and say Search. And now all those actions get fired off in my app. Yeah, this is super handy for things like login screens when you get really tired of entering the same username and password over and over again. You can totally automate this and it works great when you have to log in as different users that have different levels of permission. You can create as many custom commands as you want, so you could have one custom command to log in as one person and another customer command to log in is another one. We're starting to use this a lot, but anything you need to automate that would make your life easier. Maybe you need to get five screens down to look at something. You can create a custom command for that. So that was kind of a whirlwind tour of the major features. But what I hope you are able to see is that with just those few lines of configuration, you instantly got access to all kinds of things going on in your app. You see better stack traces, particularly if they're asynchronous you get to see details of API calls, you get to see what's going on with your ACNC storage, you get to see what's going on in your store and all of the actions that get fired. And by the way, this app uses Redux. But if you're following what we've been doing with Ignite, you know that we're using Mabex State Tree more and more. Most of what you see here works in Mabek State tree right now as well, with a separate plugin. And there's more coming as we certainly get more involved with it. And all of this became available to you without having to tool your code. And best of all, without having to change into a different runtime environment. It's the exact same environment. A couple of other tricks up at sleeve. If you use Storybook, then you can click a button in React native and your device will go into storybook mode. If you like to get your UI is Pixel perfect and we hope that you do, you're probably used to this little dance. You've got your screenshot of your mock up that you got from your designer. You put that on your screen next to your emulator and you go back and forth and try to figure out if you've got the pixels lined up with Reactotron. You can take that screenshot, drop it into Reactatron and it will display it as a semi transparent overlay in your device so you can see exactly where you went wrong and how to correct it. And it's not called React native Atron it's called Reactotron. It will work with React JS. You can use it for your web projects as well. What else can it do? Well, that's up to all of you. It's free and it's open source and like I said it's got a plug in architecture and some plugins can be created with just a few lines of code so anything you can think of along these lines anything that's specific for your app you can develop it, drop it in and make it work for you. I'm almost out of time but I want to say some thanks. First of all, Jenna Fucci is one of our designers here at Infinite Red. She's been hard at work at the lion share of the beautiful designs you've seen here and she took time out of her busy schedule to make my slides look as good as they do which on my own they wouldn't have. A big thanks to Steve Kellock for coming up with reactotron in the first place and for being patient as I pestered in with stupid questions getting ready for this talk and a big thanks, of course to all the reactor on contributors who created all this wonderful stuff that you see. I particularly want to mention Rich Evans who's here today. He's been a huge contributor to reactatron and knows it inside and out so if you have any questions definitely find him. He's got the score. If you'd like to give react to Tron a try we hope that you will best place to start is the project page on GitHub. If you have any questions or have ideas definitely come talk to us in our community slack which we talked about earlier we've got a reactor Tron channel in there so there's people in there that are ready to take your call and we really hope you'll give reactor on a try and hope that you'll discover as we did that it can take your developer experiences react native up to another level thank you very much, bye.