React.js on Rails
CC Attribution - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Chan, Michael
React is the best way to bring interactive UIs to your Rails apps. But using React.js on Rails can be hard. NPM libraries are difficult to include, JSX seems nonsensical, and “can we still use CoffeeScript?” There’s not one obvious path for working with React.js on Rails. In this talk, we’ll review the sordid past of Rails and JavaScript, explore the complementarity of React and Rails, and navigate the woes of integrating with NPM. We’ll discover why React is a natural fit for Rails today and how to make Rails love React in the future.
 All right, let's get this thing started. How the heck is everyone? I don't need more than that. Come on. How the heck is everybody? Thank you. Thank you. It makes me feel more comfortable. Thank you so much for coming to this humble little talk. I'm really glad that of all the talks out there, you decided to come to this one. I'm feeling the feels right now. So in this talk, we're going to talk about JavaScript. I feel like I won a lottery being able to talk about JavaScript at a Ruby conference. I feel like it's one of those pieces of the Rails stack that's still just pretty terrible in general. And we have an opportunity to talk about how to make it a little bit better. But it's interesting at this particular conference, there's actually been a lot of talk about JavaScript talking about like prepper backpacks and like the zombie apocalypse and whether or not JavaScript should be in your zombie apocalypse prepper backpack. Try to say that five times fast. And so I wanted to tell you just about how we solved the JavaScript problem or not how we solved it, but how we're using the right view framework to help us write better Rails apps and better JavaScript on those Rails apps. My name is Michael Chan. Go by Chan Tastic on Twitter. And there's a much younger, happy version of me you might find there. So I work on an application called Services. It was launched in 2006 and started on Rails 1.13. Services is an application for churches, actually. It helps churches organize volunteers. There are timelines, services, all that kind of stuff. It's pretty cool. And believe it or not, there is actually a market for church software. So I mean, it started in 2006. So our approach to JavaScript has kind of been, yes, write it. And as you know, after a little bit of time, sprinkles tend to turn into mountains. So we needed a way to better structure our JavaScript applications, right? So in 2012, when we were writing our second app, we started to kind of look at the landscape and see what people were doing. So we looked at bigger Rails shops. We looked at Shopify. And they were just starting to work on a project called BatmanJS. Has anyone in here used BatmanJS? Oh, good for you guys. Or good for you all. Yeah. So anyway, so we did this. And it was really interesting. I mean, it had all of the kind of markers of a 2012 JavaScript framework. It was two-way binding. And you know, you set up a whole bunch of observers to kind of track state and update things and whatnot. And so we built our application in two pieces. We had the API on one side and we had the client-side app that customers actually interfaced with. Now, this actually created a whole new host of problems for us, right? Because now we had two sets of controllers and two sets of models and two sets of validations and two routers. And like, you don't realize how much you really enjoy Form 4 until you don't have it anymore. And it's like, it's terrible. So really, our app started to feel like this, right? We just had like two cakes stacked on top of each other. And like, this was a terrible situation. Any change in the front-end app resulted in a change in the back-end app. And it was just no good. We sort of changed this app. But I asked the product manager for that team. I said, okay, do you have any particularly juicy cards where state was like just unbearable in our Batman app and was kind of solved in our, when we moved it back to just Rails. And he said, are you kidding? Like, all of them, he then proceeded to send you like eight cards and eventually gave up and said, okay, just search for cards that have hard refresh in them. And so what this means is we had, so we had parts of our app that were so unreliable. The best solution for our JavaScript application was just to say like, oh, if a user ever comes to this route, it's probably not going to work. Let's just refresh it. It's ridiculous. So as you can imagine, or as you might know, Shopify kind of abandoned BatmanJS in 2014. We're kind of like left holding his hand. Like, what do we do? And they've actually been pretty vocal against ClientSide MVC since then. So this is Toby, the CEO there, just talking about how ridiculous ClientSide is. I think he tweeted at some point about how the Batman project could cost them like $100,000 or something like that. Just up in smoke. And as David mentioned yesterday, or on Tuesday, Shopify has been really instrumental in kind of building out TurboLynx 3. So again, we kind of followed Shopify's lead. And as we built the rest of our apps or rebuilt some of our Batman apps, we rebuilt them squarely on the Rails path, right? And Rails paths, Sprinkles, SJR, TurboLynx. And actually, to be honest, we kind of like it. I know that's controversial in here, but we're pretty into it. But we're still writing a lot of JavaScript. There were a lot of places. This is from a pull request that was opened. It's just a gift kind of like showing something where we have a lot of transient state. This isn't an event that's going to get sent to the server and then respond with some server-rendered JavaScript, right? This is purely for the user. This is just a user interaction. It doesn't need to be handled by a Rails controller. We also have pages that are like fully real time. So as I was saying, we have services. We have a service that helps you plan services. And then this is kind of like a rundown for that. And this happens in real time. We use pusher to connect to a ton of devices. We have iOS devices. And the person running the presentation can move through, and that's going to kind of change these items. It tracks how much time has gone by. There's like a real-time chat thing. It's like, I mean, it's pretty exciting. It's like a JavaScript NBC person's dream. So what we needed was we needed something that would actually scale from these small interactions that we needed it for to these big full-on pages of our applications where everything was real-time. We found React to be instrumental in that and instrumental in us being able to stay on the Rails path but then just use as little JavaScript as we needed to solve a job. Particularly this concept of React components. So we'll talk about that a little bit more. I have two goals for this talk. So my first goal is that you'd be able to walk out of here and ship a React feature in an hour. It takes you like five minutes to set up and then you have 55 minutes to code. So that's my goal. If any of you accomplish it, tell me and I'll give you a digital high-five. And then my second goal is that you don't make the same mistakes that we did. We made a ton of mistakes. As you can see, we made a ton of mistakes in JavaScript and we made a ton of mistakes just porting our application logic to React. So I don't want you to make the same mistakes that we did. I'm going to try to show you kind of the ideal path that we're using right now for all of our new development. So let's do a React primer. React is a JavaScript library by Facebook. It's for creating user interfaces using components. Components do three things. They render, they receive props, and they maintain state. You do pretty well to think about a React component as a partial with locals. So let's say we have an audio service and we want to show the songs that are in this album, right? So this partial should make sense to anyone who's done Rails for a day. And so that will render out something like this. It will render out an un-loaded list of songs. This particular list is 1989 by Taylor Swift. Yes. Thank you. I may or may not have been able to create this list from my mind, but... So we're just going to do the easiest steps we can, right? We're just going to create a new partial file. We'll just dump the whole thing in there and then we'll say render songs, right? Easy. So now if we really want this to be reusable, right, we can't say album songs here, right? We want to kind of abstract that a little bit. And so we'll just say songs. We'll require some type of local data. And then our view, we update this to say, okay, songs is going to be album songs. And so now if we want to show a list of Taylor Swift albums, these are... Each of these albums has to have at least 50 plays on my iTunes. This is the best. So we're just going to iterate over the albums. I'm going to spit out a title and we're going to use our partial again. Now these are different, but because we're sending songs in as locals, it doesn't matter. The partial doesn't care. So you know this. So let's do it in JavaScript now. So instead of render partial, we have a little helper called React Component. And instead of using songs, which is going to look for the songs partial, we would use the songs, which is going to look for the songs component, the window object. Yeah. Which one? Oh, sorry. Yeah, yeah. So I'm going to... Sorry, this is the same partial code. I'm just blocking parts of it out. So... All right. So now we're going to grab songs off of the... Wow, these look terrible now. Thank you. Thank you for that. So we're going to use the songs component off the window object. Instead of sending locals in, we just send a hash in. But it's the same thing. We just say songs, album songs. And in React, we call these props short for properties. So props are immutable, kind of. If you were at... Who does Rust talk yesterday? He talked about how Rust has this concept of ownership and borrowing, and how ownership is the right to destroy or modify something. And when you pass something down as props, like, that component should not modify or destroy it. Like, they just have the ability to view and use it. So let's define our component. Can everyone see this now? Everything's looking good? Okay, cool. We have a songs variable. Let's say React create class. That's a class with a render function. Okay, we're going to render out an unordered list. We're going to grab the songs off of props. And we're going to iterate over it with map. So it's a little bit different than the Ruby code above it. And because we're going to have blocks, we're going to actually call function for each of these... For each of these items. We're just going to take the song and spit it out as a list item, song.name. All right. Let's go over that one more time again, just real quick. So we have songs. It's a React class. Has render function. UL. Grabbed the songs off of props. Maps over them. Calls this function for each song and returns a list item with a song name. Okay, so let's practice. So I had this idea of let's take a Rails app that everyone here knows about. We'll take the 15-minute blog and we'll add some real-time comments to it. Whoa! Okay, so if you haven't seen the 15-minute blog, this is the inverted version of the 15-minute blog. So there's a block in there like this where we have posts. We're going to iterate over each comment and spit out the comment body with an HR because it's 2003. So let's go straight to React. So we'll create a comment. It's a React class with a render function and that render function is going to return a div with an HR in it. And we're going to take our comment right off of props and interpolate that out. Okay, pretty simple. So here in our view, we're going to use our React component helper. We're going to spit out the comment component. Man, it's hard to say. I should have chosen a different example. Comment component and use the comment body there, right? So our app goes from looking like this to looking like this. The astute viewer will say those look exactly the same and they would be correct. Except now, these two comments are being rendered in JavaScript. So that's pretty cool. So let's do the rest of this. We're going to take the whole block now. We saw this with songs. We're going to create comments. It's a React class, the render function, spits out a div, takes all the comments, maps over them, runs this function for each. We're going to pull out the body of the comment and in React, we have this cool syntax where we can use our comment like an HTML tag, right? So we didn't have to do anything. We just run that. And we can send in a comment like we were with props as an HTML attribute. So that's cool. So we're just going to send in the body. Cool. Take that out. Change this to comments. Send all the comments down. And now our app goes from looking like this to looking like this. The astute observers again say that looks exactly the same and you are correct. Except now, the entire comment block is rendered in JavaScript. This is pretty cool. So let's get to the real time bit. So we have a comments component that renders out comments. We have a comment component that renders out a single comment. We're going to create a comments container. You can think about this kind of like a Rails controller, right? So this comments container, it knows how to fetch comments and it knows which component to render when it has the comments it wants. So you can think about this kind of like a Rails controller. This isn't special. It's just kind of a convention, this container convention. So here we're going to kind of ditch all the stuff that we had before we were rendering out the comments directly. And we're going to now give, so we're going to use the comments container. And we're going to give it a path now and say, hey, this is where you're going to fetch comments. This is where you're going to fetch the JSON for comments. This is where that comments container looks like. This first half is the fetching of comments. We have our render function at the bottom. And we have this get initial state. So these are the APIs that we're going to talk about. These are just the things that we haven't talked about yet. These are for kind of managing state and whatnot. These are the place where we actually interact with and set that state. So let's dive into it. So we have a comments container. It returns a comments component. And we're going to start by just giving it comments of like an empty array. So this is going to render out nothing. This is our first interaction with state. So we have a special object for that and react. There's props and state. It's the only two ways that you interact with data. This is the second of those. This is state. So where props is mutable, state is designed to change. This comments container knows what state comments is in. And it knows how to get new comments and how to set those comments. So now we can use this API called get initial state. And this is just a way to kind of protect ourselves when we're doing an asynchronous call to the first time we render with an empty state at least. Not send undefined all over the place. So again, we're getting our state from comments state. All right. So this is our function. This is pretty simple. We're actually going to take the comments path prop that we sent in and we're going to fetch that JSON on six, oh, sorry, that we passed in from that view. On success, we're going to take that data and we're going to use a special function called set state. I'm going to say, hey, state is now the new data that we got back. You can think about this set state as like a refresh button for your component. Okay. Anytime you call this method with new state, it's going to totally re-render anything that's downline of that tree. So in that case, it's going to render our comments component and subsequently every component after that. We have another hook here that we can use. It's called component will mount. That's just an initializer function. When this component is ready to go, it's initialized, we can run this function and here we're just going to say, hey, get all the comments. We want to do that every second. We're going to use polling for now. I'll show you some more interesting examples later. Now for the first time, we actually see a change. Hopefully you can see it. But as I add comments to the left screen, they're going to get loaded in the right screen. This isn't particularly exciting, but we didn't write a whole lot of code to get here. The code that we wrote is all in one place. It's totally isolated to those three component files. We didn't have to change a JavaScript file and update our view to have a DOM and all that kind of stuff. It's all there. This is totally isolated. We can implement it totally differently in the future if we need. It's very cool. So another cool thing about React that I want to show you is it's very smart about the way that it does updates. Might be kind of hard to see, but if you look at that list of comments, you'll see that it's only doing an insert of the last comment that I added. So the way this works is that React does re-render on every set state. So right here, we're setting state with new comments. It does re-render, but it renders in memory and it just does a diff to say, hey, how am I different than the DOM? And it says, okay, we need to change these few things and then we'll be up to date. But it doesn't grab the whole thing out and then just do an insert of the whole comment block. This is also pretty cool for a lot of performance reasons. So I showed you about four things right there to actually manipulate states. So what are a lot of ‑‑ what are the number of things that you need to know to be effective with React right off the bat? Well, it's not too many. I'll show you a couple of things that I've shown you already and those that we haven't. So first, this is how you render out a component in your jobs ‑‑ or in your Rails views. This is how you send in props. Super easy. So this is a greeting component. We're going to say hi, Bob or something like that. This is how you define a component. We're just returning an H2 that says hi and we're interpolating the name out. There's a thing called prop types which is pretty cool where you can actually specify what type name should be, which is really handy when you want to read for the reusability of these components. It's really awesome because now in development, if someone tries to use this greeting component and they're not quite sure how it works, if they try to send in a number, they're going to get a really cool error like this ‑‑ or warning like this in the console. It's just going to say, hey, you're trying to use greeting but you're sending in a number as name and we really need a string. There's a method called get default props and this is kind of like set initial state or get initial state where you ‑‑ where you can set initial value. So if someone uses this component and they don't pass in a name, we're just going to say yes. So we'll say hi, guest. You can kind of think of this as like an or equals in Ruby. Set state, this is like the refresh button of your React components. Get initial state, you saw this. We can kind of set an initial state for our component. Component will amount. This is where you would do things like get JSON. As soon as the component is ready, we're going to fire off something and get some new data and handle that data. It also has a sibling called component will unmount and this is for things like if you are attaching event listeners. So you would have component will amount and component will unmount as this component goes in and out of view. You would attach event listener and then you would kind of remove that event listener and clean up after yourself. This works if you were using server‑cent events. With pusher, we're using pusher. Pretty cool. So it's about nine things you need to know. Like, that's not a lot of things, right? Not a lot of things. Are you guys alive out there? You gals alive out there? Everybody alive out there? This is a nine thing. This is an incredibly small amount of things that you need to know. We're not telling it how to be smart about updates. It's just doing that by itself. We're not grabbing dom nodes and changing them out and doing all this stuff. We're just saying, hey, we want this to render whatever the state is just like render that state. Every time you render, just do it the right way and then figure out on your own time how to insert in the most effective way. So I want to show you a little example. This is from our services live app that I was telling you about in the beginning. So if you watch, you can see the clock in the app. It looks so weird. So you can see the clock. And you can see on the right, the only update that's happening is that inner HTML. Which is really cool. This entire app is re-rendering and it's just sending in the new time. So we're getting second snapshots of this application. Here's the chat application. As I add comments, you can look in the table right there. It's just going to insert those table rows. So I want to talk, shift a little bit to implementation. So this is something we struggled with a lot. There was, at one point, every single app that we had that used React was doing it a different way. So I'm not going to tell you all five or six ways that we were doing it, but I will tell you the way that we landed on, the way that we feel is the most effective and the most honoring of Rails. And that's the pipeline. So we use React Rails gem. This buys you a couple things. It buys you that helper that I was telling you about, the React component helper that we've been using in all these examples. It's really smart. It uses UJS to mount and unmount your components. And it's really smart about turbo links. So whether you use turbo links or don't use turbo links, it's going to do the right thing. It's very simple to set up. You just add this gem. You run this installer. And installer is really pretty minimal. All it does is really give you a components directory to put all your components in. It also gives you this really cool generator. So you just say, React component greeting, and it'll spit out this really cool, you know, all the code you need to render out a greeting. It allows you, it has a nice little syntax for prop types. So if you know that you need a name and a string, it'll render out this for you. With the prop types in the top. So if you haven't used Rails assets, this is an incredibly cool project. What it does is it works on Bower. And so it will, here, let's see, it works on Bower. So in your gem file, all you have to do is add this source block. And then you add the, you add these gems that you can find on the Rails assets site. And so as you can see, there's just a prefix that it rails assets alts, rails assets, React router, whatever. And what Rails assets does is it works on Bower and it'll pull down the Bower repository alt or React router or moment.js. It'll pull that down and it will create an honest to goodness gem for you and return that to you. So you have like an honest to goodness gem created from a Bower JavaScript or CSS repository. This is super easy. This is the easiest way that we found to be able to pull cool JavaScript libraries into our Rails apps. So the mistake we made was fighting the asset pipeline. We worked a lot with trying to use browser file, webpack, and all this kind of stuff. And there are benefits there and I'd be happy to talk with you afterwards about what those are. But we found that for the most part, the easiest solution was the best solution for us. So this is great. It communicates well and our teams are really happy with it. Let's talk about languages. So some of you might have been watching and saying, like, okay, I don't understand what this magic is happening, the whole HTML and JavaScript. So some of you might have heard the controversy around JSX. I don't really think this is a big deal. I like it. I like seeing JavaScript right here in my components. It's nice that I don't have a separate file that's doing this. At the end of the day, it's no different than the way, like, ERB works or handlebars works. It's just processing out, it's pre-processing our JSX into function calls like this. But we don't have to look at that. We don't have to write that. We can just write it as if we were writing HTML. All right. So that's the JavaScript one. React Rails comes out of the box with support for coffee scripts. So you just pen the coffee on the back. So you lose a couple brackets and parentheses and whatnot. The weird part is that you have to back tick escape out the JSX, which isn't a huge problem if you really love coffee script that much. We don't, so we just don't use it. It's also weird that you have to use this because this is being back tick escaped. You can't use at inside your component. You can use it everywhere else, but I'm sorry, inside the template. You can use it everywhere else, but not inside the template. So what we've really come to love is ES6. There's a little flag you can set up in the React Rails gem that will convert ES6 into ES5 for you. So this is great. Now this has a little bit of a difference in text, which is fine. You get used to it. We really love it because it buys us all the things that we really love about coffee script, but not coffee script, and we can just return this JSX right there. So the first thing that's a little bit different is that you define things as a class, so we define this as a greeting class, and it extends React components. So before we were creating, we were using Create Class to define our components. Here we're going to just extend the class React component. Also, prop types get pulled out of the class, and they're used as a constructor property. Two things, pretty simple. One nice thing is that you can actually, React is extremely smart, and I was telling you about the great warnings and errors that you can tie into. So if you try to use an API that's strictly dedicated to the Create Class way of doing things, when you try to do this as a class, you're going to get a warning, and it's going to say, hey, getInertialState was defined on comment, a plain JavaScript class. This is only supported for classes created using react.create class. Did you mean to define a state property instead? This is an amazing error, and it's all just switching from JavaScript to ES6, and they're doing amazing. I don't even know how they figure this out for me, and they're telling me exactly what I need to do. They're telling me where I need to solve this problem, and what I'm doing wrong, what I need to do. You can learn a thing or two about copywriting from this error. This is amazing. Anyway, so we go and, oops, we changed that to the right thing, which I apparently don't have a slide for. So early on, we made the mistake of not embracing JSX. We did a lot of somersaults to try to get around using JSX and just drawing out the functions ourselves and coffee script and whatnot, and we found that the best path is just to embrace JSX. You really start to love it after about, like, an hour, and this is where Facebook and the React team is hiding a lot of the implementation details from you. So the most painful updates that we've ever had are the ones where we were trying to use coffee script instead of JSX, and something wasn't hidden from us because of that. So use JSX. It's awesome. Don't make the mistake we did. Use JSX is really great, and I'm starting to see more and more documentation in React using JSX. I think it's the way moving forward. A lot of people who are using React really embrace JSX. So I want to leave you this morning with just this concept of only as much JavaScript as you need. The idea here is stick to the Rails path as much as you can, and just do the minimal amount of JavaScript you need, and I feel like React helps you there. So this is our, oh, man, my cakes look all funky now. So this is your Rails app. Inverted. This is your Rails app with sprinkles. This is your Rails app after two years of sprinkles. This is your Rails app using a client-side NBC. And this is what I imagine TurboLinks 3 to be like, where you're actually using the sprinkles to kind of like pin down the Ruby views on top of the cake, but I don't know. And this is the party that we're having with React JS at Planning Center. Thanks so much.
 All right, let's get this thing started. How the heck is everyone? I don't need more than  that. Come on. How the heck is everybody? Thank you. Thank you. It makes me feel more  comfortable. Thank you so much for coming to this humble little talk. I'm really glad  that of all the talks out there, you decided to come to this one. I'm feeling the feels  right now. So in this talk, we're going to talk about JavaScript. I feel like I won a  lottery being able to talk about JavaScript at a Ruby conference. I feel like it's one  of those pieces of the Rails stack that's still just pretty terrible in general. And  we have an opportunity to talk about how to make it a little bit better. But it's interesting  at this particular conference, there's actually been a lot of talk about JavaScript talking  about like prepper backpacks and like the zombie apocalypse and whether or not JavaScript  should be in your zombie apocalypse prepper backpack. Try to say that five times fast.  And so I wanted to tell you just about how we solved the JavaScript problem or not how  we solved it, but how we're using the right view framework to help us write better Rails  apps and better JavaScript on those Rails apps. My name is Michael Chan. Go by Chan  Tastic on Twitter. And there's a much younger, happy version of me you might find there.  So I work on an application called Services. It was launched in 2006 and started on Rails  1.13. Services is an application for churches, actually. It helps churches organize volunteers.  There are timelines, services, all that kind of stuff. It's pretty cool. And believe it  or not, there is actually a market for church software. So I mean, it started in 2006. So  our approach to JavaScript has kind of been, yes, write it. And as you know, after a little  bit of time, sprinkles tend to turn into mountains. So we needed a way to better structure our  JavaScript applications, right? So in 2012, when we were writing our second app, we started  to kind of look at the landscape and see what people were doing. So we looked at bigger  Rails shops. We looked at Shopify. And they were just starting to work on a project called  BatmanJS. Has anyone in here used BatmanJS? Oh, good for you guys. Or good for you all.  Yeah. So anyway, so we did this. And it was really interesting. I mean, it had all of  the kind of markers of a 2012 JavaScript framework. It was two-way binding. And you know, you  set up a whole bunch of observers to kind of track state and update things and whatnot.  And so we built our application in two pieces. We had the API on one side and we had the  client-side app that customers actually interfaced with. Now, this actually created a whole new  host of problems for us, right? Because now we had two sets of controllers and two sets  of models and two sets of validations and two routers. And like, you don't realize how  much you really enjoy Form 4 until you don't have it anymore. And it's like, it's terrible.  So really, our app started to feel like this, right? We just had like two cakes stacked  on top of each other. And like, this was a terrible situation. Any change in the front-end  app resulted in a change in the back-end app. And it was just no good. We sort of changed  this app. But I asked the product manager for that team. I said, okay, do you have any  particularly juicy cards where state was like just unbearable in our Batman app and was  kind of solved in our, when we moved it back to just Rails. And he said, are you kidding?  Like, all of them, he then proceeded to send you like eight cards and eventually gave up  and said, okay, just search for cards that have hard refresh in them. And so what this  means is we had, so we had parts of our app that were so unreliable. The best solution  for our JavaScript application was just to say like, oh, if a user ever comes to this  route, it's probably not going to work. Let's just refresh it. It's ridiculous. So as you  can imagine, or as you might know, Shopify kind of abandoned BatmanJS in 2014. We're  kind of like left holding his hand. Like, what do we do? And they've actually been pretty  vocal against ClientSide MVC since then. So this is Toby, the CEO there, just talking  about how ridiculous ClientSide is. I think he tweeted at some point about how the Batman  project could cost them like $100,000 or something like that. Just up in smoke. And as David mentioned  yesterday, or on Tuesday, Shopify has been really instrumental in kind of building out  TurboLynx 3. So again, we kind of followed Shopify's lead. And as we built the rest of  our apps or rebuilt some of our Batman apps, we rebuilt them squarely on the Rails path,  right? And Rails paths, Sprinkles, SJR, TurboLynx. And actually, to be honest, we kind of like  it. I know that's controversial in here, but we're pretty into it. But we're still writing  a lot of JavaScript. There were a lot of places. This is from a pull request that was opened.  It's just a gift kind of like showing something where we have a lot of transient state. This  isn't an event that's going to get sent to the server and then respond with some server-rendered  JavaScript, right? This is purely for the user. This is just a user interaction. It doesn't  need to be handled by a Rails controller. We also have pages that are like fully real  time. So as I was saying, we have services. We have a service that helps you plan services.  And then this is kind of like a rundown for that. And this happens in real time. We use  pusher to connect to a ton of devices. We have iOS devices. And the person running the  presentation can move through, and that's going to kind of change these items. It tracks  how much time has gone by. There's like a real-time chat thing. It's like, I mean, it's  pretty exciting. It's like a JavaScript NBC person's dream.  So what we needed was we needed something that would actually scale from these small interactions  that we needed it for to these big full-on pages of our applications where everything  was real-time. We found React to be instrumental in that and instrumental in us being able  to stay on the Rails path but then just use as little JavaScript as we needed to solve  a job. Particularly this concept of React components. So we'll talk about that a little  bit more. I have two goals for this talk. So my first goal is that you'd be able to  walk out of here and ship a React feature in an hour. It takes you like five minutes  to set up and then you have 55 minutes to code. So that's my goal. If any of you accomplish  it, tell me and I'll give you a digital high-five.  And then my second goal is that you don't make the same mistakes that we did. We made  a ton of mistakes. As you can see, we made a ton of mistakes in JavaScript and we made  a ton of mistakes just porting our application logic to React. So I don't want you to make  the same mistakes that we did. I'm going to try to show you kind of the ideal path that  we're using right now for all of our new development.  So let's do a React primer. React is a JavaScript library by Facebook. It's for creating user  interfaces using components. Components do three things. They render, they receive props,  and they maintain state. You do pretty well to think about a React component as a partial  with locals. So let's say we have an audio service and we want to show the songs that  are in this album, right? So this partial should make sense to anyone who's done Rails  for a day. And so that will render out something like this. It will render out an un-loaded  list of songs. This particular list is 1989 by Taylor Swift. Yes. Thank you. I may or  may not have been able to create this list from my mind, but... So we're just going to  do the easiest steps we can, right? We're just going to create a new partial file. We'll  just dump the whole thing in there and then we'll say render songs, right? Easy. So now  if we really want this to be reusable, right, we can't say album songs here, right? We want  to kind of abstract that a little bit. And so we'll just say songs. We'll require some  type of local data. And then our view, we update this to say, okay, songs is going to  be album songs. And so now if we want to show a list of Taylor Swift albums, these are...  Each of these albums has to have at least 50 plays on my iTunes. This is the best. So  we're just going to iterate over the albums. I'm going to spit out a title and we're going  to use our partial again. Now these are different, but because we're sending songs in as locals,  it doesn't matter. The partial doesn't care. So you know this. So let's do it in JavaScript  now. So instead of render partial, we have a little helper called React Component. And  instead of using songs, which is going to look for the songs partial, we would use the  songs, which is going to look for the songs component, the window object. Yeah. Which  one? Oh, sorry. Yeah, yeah. So I'm going to... Sorry, this is the same partial code. I'm  just blocking parts of it out. So... All right. So now we're going to grab songs off  of the... Wow, these look terrible now. Thank you. Thank you for that. So we're going to  use the songs component off the window object. Instead of sending locals in, we just send  a hash in. But it's the same thing. We just say songs, album songs. And in React, we  call these props short for properties. So props are immutable, kind of. If you were at...  Who does Rust talk yesterday? He talked about how Rust has this concept of ownership and  borrowing, and how ownership is the right to destroy or modify something. And when you  pass something down as props, like, that component should not modify or destroy it. Like, they  just have the ability to view and use it. So let's define our component. Can everyone  see this now? Everything's looking good? Okay, cool. We have a songs variable. Let's say  React create class. That's a class with a render function. Okay, we're going to render  out an unordered list. We're going to grab the songs off of props. And we're going to  iterate over it with map. So it's a little bit different than the Ruby code above it.  And because we're going to have blocks, we're going to actually call function for each of  these... For each of these items. We're just going to take the song and spit it out as  a list item, song.name. All right. Let's go over that one more time again, just real  quick. So we have songs. It's a React class. Has render function. UL. Grabbed the songs  off of props. Maps over them. Calls this function for each song and returns a list item with  a song name. Okay, so let's practice. So I had this idea of let's take a Rails app that  everyone here knows about. We'll take the 15-minute blog and we'll add some real-time comments  to it. Whoa! Okay, so if you haven't seen the 15-minute blog, this is the inverted version  of the 15-minute blog. So there's a block in there like this where we have posts. We're  going to iterate over each comment and spit out the comment body with an HR because it's  2003. So let's go straight to React. So we'll create a comment. It's a React class with  a render function and that render function is going to return a div with an HR in it.  And we're going to take our comment right off of props and interpolate that out. Okay,  pretty simple. So here in our view, we're going to use our React component helper. We're  going to spit out the comment component. Man, it's hard to say. I should have chosen  a different example. Comment component and use the comment body there, right? So our  app goes from looking like this to looking like this. The astute viewer will say those  look exactly the same and they would be correct. Except now, these two comments are being rendered  in JavaScript. So that's pretty cool. So let's do the rest of this. We're going to take the  whole block now. We saw this with songs. We're going to create comments. It's a React class,  the render function, spits out a div, takes all the comments, maps over them, runs this  function for each. We're going to pull out the body of the comment and in React, we have  this cool syntax where we can use our comment like an HTML tag, right? So we didn't have  to do anything. We just run that. And we can send in a comment like we were with props  as an HTML attribute. So that's cool. So we're just going to send in the body. Cool. Take  that out. Change this to comments. Send all the comments down. And now our app goes from  looking like this to looking like this. The astute observers again say that looks exactly  the same and you are correct. Except now, the entire comment block is rendered in JavaScript.  This is pretty cool. So let's get to the real time bit. So we have a comments component that  renders out comments. We have a comment component that renders out a single comment. We're going  to create a comments container. You can think about this kind of like a Rails controller,  right? So this comments container, it knows how to fetch comments and it knows which component  to render when it has the comments it wants. So you can think about this kind of like a  Rails controller. This isn't special. It's just kind of a convention, this container  convention. So here we're going to kind of ditch all the stuff that we had before we  were rendering out the comments directly. And we're going to now give, so we're going  to use the comments container. And we're going to give it a path now and say, hey, this is  where you're going to fetch comments. This is where you're going to fetch the JSON for  comments. This is where that comments container looks like. This first half is the fetching  of comments. We have our render function at the bottom. And we have this get initial  state. So these are the APIs that we're going to talk about. These are just the things that  we haven't talked about yet. These are for kind of managing state and whatnot. These  are the place where we actually interact with and set that state. So let's dive into it.  So we have a comments container. It returns a comments component. And we're going to start  by just giving it comments of like an empty array. So this is going to render out nothing.  This is our first interaction with state. So we have a special object for that and react.  There's props and state. It's the only two ways that you interact with data. This is  the second of those. This is state. So where props is mutable, state is designed to change.  This comments container knows what state comments is in. And it knows how to get new comments  and how to set those comments. So now we can use this API called get initial state. And  this is just a way to kind of protect ourselves when we're doing an asynchronous call to the  first time we render with an empty state at least. Not send undefined all over the place.  So again, we're getting our state from comments state. All right. So this is our function.  This is pretty simple. We're actually going to take the comments path prop that we sent  in and we're going to fetch that JSON on six, oh, sorry, that we passed in from that view.  On success, we're going to take that data and we're going to use a special function called  set state. I'm going to say, hey, state is now the new data that we got back. You can  think about this set state as like a refresh button for your component. Okay. Anytime you  call this method with new state, it's going to totally re-render anything that's downline  of that tree. So in that case, it's going to render our comments component and subsequently  every component after that. We have another hook here that we can use. It's called component  will mount. That's just an initializer function. When this component is ready to go, it's initialized,  we can run this function and here we're just going to say, hey, get all the comments. We  want to do that every second. We're going to use polling for now. I'll show you some  more interesting examples later. Now for the first time, we actually see a change. Hopefully  you can see it. But as I add comments to the left screen, they're going to get loaded in  the right screen. This isn't particularly exciting, but we didn't write a whole lot  of code to get here. The code that we wrote is all in one place. It's totally isolated  to those three component files. We didn't have to change a JavaScript file and update  our view to have a DOM and all that kind of stuff. It's all there. This is totally isolated.  We can implement it totally differently in the future if we need. It's very cool. So  another cool thing about React that I want to show you is it's very smart about the way  that it does updates. Might be kind of hard to see, but if you look at that list of comments,  you'll see that it's only doing an insert of the last comment that I added. So the way  this works is that React does re-render on every set state. So right here, we're setting  state with new comments. It does re-render, but it renders in memory and it just does  a diff to say, hey, how am I different than the DOM? And it says, okay, we need to change  these few things and then we'll be up to date. But it doesn't grab the whole thing out and  then just do an insert of the whole comment block. This is also pretty cool for a lot  of performance reasons. So I showed you about four things right there to actually manipulate  states. So what are a lot of ‑‑ what are the number of things that you need to know  to be effective with React right off the bat? Well, it's not too many. I'll show you a couple  of things that I've shown you already and those that we haven't. So first, this is how  you render out a component in your jobs ‑‑ or in your Rails views. This is how you send  in props. Super easy. So this is a greeting component. We're going to say hi, Bob or something  like that. This is how you define a component. We're just returning an H2 that says hi and  we're interpolating the name out. There's a thing called prop types which is pretty  cool where you can actually specify what type name should be, which is really handy when  you want to read for the reusability of these components. It's really awesome because now  in development, if someone tries to use this greeting component and they're not quite sure  how it works, if they try to send in a number, they're going to get a really cool error like  this ‑‑ or warning like this in the console. It's just going to say, hey, you're trying  to use greeting but you're sending in a number as name and we really need a string. There's  a method called get default props and this is kind of like set initial state or get initial  state where you ‑‑ where you can set initial value. So if someone uses this component  and they don't pass in a name, we're just going to say yes. So we'll say hi, guest.  You can kind of think of this as like an or equals in Ruby. Set state, this is like the  refresh button of your React components. Get initial state, you saw this. We can kind of  set an initial state for our component. Component will amount. This is where you would do things  like get JSON. As soon as the component is ready, we're going to fire off something and  get some new data and handle that data. It also has a sibling called component will unmount  and this is for things like if you are attaching event listeners. So you would have component  will amount and component will unmount as this component goes in and out of view. You  would attach event listener and then you would kind of remove that event listener and clean  up after yourself. This works if you were using server‑cent events. With pusher, we're  using pusher. Pretty cool. So it's about nine things you need to know. Like, that's  not a lot of things, right? Not a lot of things. Are you guys alive out there? You gals alive  out there? Everybody alive out there? This is a nine thing. This is an incredibly small  amount of things that you need to know. We're not telling it how to be smart about updates.  It's just doing that by itself. We're not grabbing dom nodes and changing them out and  doing all this stuff. We're just saying, hey, we want this to render whatever the state  is just like render that state. Every time you render, just do it the right way and then  figure out on your own time how to insert in the most effective way.  So I want to show you a little example. This is from our services live app that I was telling  you about in the beginning. So if you watch, you can see the clock in the app. It looks  so weird. So you can see the clock. And you can see on the right, the only update that's  happening is that inner HTML. Which is really cool. This entire app is re-rendering and  it's just sending in the new time. So we're getting second snapshots of this application.  Here's the chat application. As I add comments, you can look in the table right there. It's  just going to insert those table rows. So I want to talk, shift a little bit to implementation.  So this is something we struggled with a lot. There was, at one point, every single app  that we had that used React was doing it a different way. So I'm not going to tell you  all five or six ways that we were doing it, but I will tell you the way that we landed  on, the way that we feel is the most effective and the most honoring of Rails. And that's  the pipeline. So we use React Rails gem. This buys you a couple things. It buys you that  helper that I was telling you about, the React component helper that we've been using in  all these examples. It's really smart. It uses UJS to mount and unmount your components.  And it's really smart about turbo links. So whether you use turbo links or don't use  turbo links, it's going to do the right thing. It's very simple to set up. You just add this  gem. You run this installer. And installer is really pretty minimal. All it does is really  give you a components directory to put all your components in. It also gives you this  really cool generator. So you just say, React component greeting, and it'll spit out this  really cool, you know, all the code you need to render out a greeting. It allows you, it  has a nice little syntax for prop types. So if you know that you need a name and a string,  it'll render out this for you. With the prop types in the top. So if you haven't used Rails  assets, this is an incredibly cool project. What it does is it works on Bower. And so  it will, here, let's see, it works on Bower. So in your gem file, all you have to do is  add this source block. And then you add the, you add these gems that you can find on the  Rails assets site. And so as you can see, there's just a prefix that it rails assets  alts, rails assets, React router, whatever. And what Rails assets does is it works on  Bower and it'll pull down the Bower repository alt or React router or moment.js. It'll pull  that down and it will create an honest to goodness gem for you and return that to you.  So you have like an honest to goodness gem created from a Bower JavaScript or CSS repository.  This is super easy. This is the easiest way that we found to be able to pull cool JavaScript  libraries into our Rails apps. So the mistake we made was fighting the asset pipeline. We  worked a lot with trying to use browser file, webpack, and all this kind of stuff. And there  are benefits there and I'd be happy to talk with you afterwards about what those are.  But we found that for the most part, the easiest solution was the best solution for us. So  this is great. It communicates well and our teams are really happy with it.  Let's talk about languages. So some of you might have been watching and saying, like,  okay, I don't understand what this magic is happening, the whole HTML and JavaScript.  So some of you might have heard the controversy around JSX. I don't really think this is a  big deal. I like it. I like seeing JavaScript right here in my components. It's nice that  I don't have a separate file that's doing this. At the end of the day, it's no different  than the way, like, ERB works or handlebars works. It's just processing out, it's pre-processing  our JSX into function calls like this. But we don't have to look at that. We don't have  to write that. We can just write it as if we were writing HTML.  All right. So that's the JavaScript one. React Rails comes out of the box with support  for coffee scripts. So you just pen the coffee on the back. So you lose a couple brackets  and parentheses and whatnot. The weird part is that you have to back tick escape out the  JSX, which isn't a huge problem if you really love coffee script that much. We don't, so  we just don't use it. It's also weird that you have to use this because this is being  back tick escaped. You can't use at inside your component. You can use it everywhere  else, but I'm sorry, inside the template. You can use it everywhere else, but not inside  the template. So what we've really come to love is ES6. There's a little flag you can  set up in the React Rails gem that will convert ES6 into ES5 for you. So this is great. Now  this has a little bit of a difference in text, which is fine. You get used to it. We really  love it because it buys us all the things that we really love about coffee script, but  not coffee script, and we can just return this JSX right there. So the first thing that's  a little bit different is that you define things as a class, so we define this as a  greeting class, and it extends React components. So before we were creating, we were using  Create Class to define our components. Here we're going to just extend the class React  component. Also, prop types get pulled out of the class, and they're used as a constructor  property. Two things, pretty simple. One nice thing is that you can actually, React is extremely  smart, and I was telling you about the great warnings and errors that you can tie into.  So if you try to use an API that's strictly dedicated to the Create Class way of doing  things, when you try to do this as a class, you're going to get a warning, and it's going  to say, hey, getInertialState was defined on comment, a plain JavaScript class. This  is only supported for classes created using react.create class. Did you mean to define  a state property instead? This is an amazing error, and it's all just switching from JavaScript  to ES6, and they're doing amazing. I don't even know how they figure this out for me,  and they're telling me exactly what I need to do. They're telling me where I need to  solve this problem, and what I'm doing wrong, what I need to do. You can learn a thing or  two about copywriting from this error. This is amazing. Anyway, so we go and, oops, we  changed that to the right thing, which I apparently don't have a slide for. So early  on, we made the mistake of not embracing JSX. We did a lot of somersaults to try to get  around using JSX and just drawing out the functions ourselves and coffee script and  whatnot, and we found that the best path is just to embrace JSX. You really start to  love it after about, like, an hour, and this is where Facebook and the React team is hiding  a lot of the implementation details from you. So the most painful updates that we've ever  had are the ones where we were trying to use coffee script instead of JSX, and something  wasn't hidden from us because of that. So use JSX. It's awesome. Don't make the mistake  we did. Use JSX is really great, and I'm starting to see more and more documentation in React  using JSX. I think it's the way moving forward. A lot of people who are using React really  embrace JSX. So I want to leave you this morning with just this concept of only as much JavaScript  as you need. The idea here is stick to the Rails path as much as you can, and just do  the minimal amount of JavaScript you need, and I feel like React helps you there. So  this is our, oh, man, my cakes look all funky now. So this is your Rails app. Inverted.  This is your Rails app with sprinkles. This is your Rails app after two years of sprinkles.  This is your Rails app using a client-side NBC. And this is what I imagine TurboLinks  3 to be like, where you're actually using the sprinkles to kind of like pin down the  Ruby views on top of the cake, but I don't know. And this is the party that we're having  with React JS at Planning Center. Thanks so much.
React_0_47.png React_48_155.png React_156_299.png React_300_887.png React_888_2303.png React_2304_2423.png React_2424_3431.png React_3432_3803.png React_3804_5723.png React_5724_6875.png React_6876_7079.png React_7080_7619.png React_7620_8555.png React_8556_10079.png React_10080_10787.png React_10788_11915.png React_11916_13247.png React_13248_14195.png React_14196_15407.png React_15408_17843.png React_17844_18095.png React_18096_19955.png React_19956_20927.png React_20928_21371.png React_21372_26519.png React_26520_27383.png React_27384_28535.png React_28536_28811.png React_28812_32147.png React_32148_34187.png React_34188_34295.png React_34296_35399.png React_35400_36359.png React_36360_36659.png React_36660_37823.png React_37824_38411.png React_38412_43643.png React_43644_43739.png React_43740_43787.png React_43788_45659.png React_45660_46043.png React_46044_46163.png React_46164_46763.png React_46764_46847.png React_46848_46907.png React_46908_46967.png React_46968_47075.png React_47076_47077.png