We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

React on Rails

00:00

Formal Metadata

Title
React on Rails
Title of Series
Part Number
59
Number of Parts
86
Author
License
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
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
Abstract
Eighteen months ago, our fairly typical Ruby on Rails app had some mundane client side interactions managed by a tangle of untested JQuery spaghetti. Today, new features are built with React, CSS modules, and a far better UX. With ES6 front end code, processed with Babel, compiled (and hot-reloaded in development) with Webpack, and tested with Jest – all within the same Rails application. Come along to this talk to hear how we migrated our app a piece at a time to use technologies that don’t always sit naturally alongside Rails. I will cover technical implementations and lessons learned.
35
Web applicationResultantMemory managementArchaeological field surveyProduct (business)Java appletSoftware developerMathematical analysisScripting languageGroup actionRuby on RailsComputer animation
Software developerBitProduct (business)Front and back endsEvoluteDemosceneArchaeological field surveyInformation technology consultingResultantMathematical analysisForm (programming)Real-time operating systemMultiplication signExterior algebraWordDependent and independent variablesPower (physics)AreaInteractive televisionXMLComputer animation
Arithmetic meanVideoconferencingMassMultiplication signFlow separationInteractive televisionIntegrated development environmentDefault (computer science)Game theoryFront and back endsSoftware frameworkLibrary (computing)Line (geometry)InternetworkingOcean currentBootstrap aggregatingGraphical user interfaceVideo gameSoftware developerSoftware testingWeb 2.0Computer fileFormal languageBitTwitterStructural loadPoint (geometry)Web browserConnectivity (graph theory)Revision controlFrame problemStaff (military)Process (computing)Physical lawQuery languageSoftware bugState of matterMathematicsSmoothingPresentation of a groupScripting languageResultantMathematical analysisComputer animation
Web pageCategory of beingMultiplication signSlide ruleProcess (computing)Web browserString (computer science)Open sourceView (database)Different (Kate Ryan album)InterpolationState of matterTerm (mathematics)Software frameworkMessage passingRight angleLogical constantFunctional (mathematics)Revision controlNeuroinformatikConnectivity (graph theory)BuildingBitSet (mathematics)Phase transitionFormal languageDivisorAxiom of choiceInformationRepresentation (politics)Template (C++)FacebookFitness functionMaxima and minimaScripting languageCodeVolumenvisualisierungCore dumpPresentation of a groupArtistic renderingEndliche ModelltheorieIsochoreMereologyElement (mathematics)Transportation theory (mathematics)PolygonACIDSemiconductor memoryGauß-FehlerintegralDecision theoryGroup actionCoefficient of determinationSoftware developerCursor (computers)1 (number)Query languageSocial classExpert systemNumberPosition operatorMobile appEntire functionNetwork topologyElectronic mailing listArrow of timeSoftware repository
Product (business)Software developerRight angleWeb pageComputer fileModule (mathematics)Source codeConnectivity (graph theory)Figurate numberDefault (computer science)Multiplication signFunction (mathematics)Attribute grammarFiber bundlePoint (geometry)CodeProcess (computing)Hash functionClient (computing)Content (media)SatelliteOrder (biology)Template (C++)State of matterFormal languageLevel (video gaming)Web browserPredicate (grammar)Integrated development environmentMappingScripting languageBitWeb 2.0Compilation albumAreaPerturbation theoryACIDEndliche ModelltheorieForestWebsiteJava appletMereologyMedical imagingNetwork topologyRevision controlMathematicsError messageComputer animation
RoutingState of matterCodeModule (mathematics)Software testingProduct (business)Library (computing)Scripting languagePlug-in (computing)Function (mathematics)LogicWeb browserConnectivity (graph theory)Set (mathematics)Process (computing)Information technology consultingGroup actionObject (grammar)Source codeMaxima and minimaComplex (psychology)Artistic renderingExecution unitCompilerDependent and independent variablesSingle-precision floating-point formatVirtual machineCompilation albumWeb 2.0Utility softwareComputer filePoint (geometry)MathematicsMappingStatement (computer science)Software frameworkMultiplication signMereologySoftware developerFunctional (mathematics)CurveCartesian coordinate systemEndliche ModelltheorieBranch (computer science)Integrated development environmentCoefficient of determinationFront and back endsUnit testingSocial classNormal (geometry)Lattice (group)Hash functionBlogImplementationPlastikkarteFluxDefault (computer science)Data storage deviceFocus (optics)Level (video gaming)Combinational logicMobile appFacebookRouter (computing)Data managementWeb pageSoftware bugSatelliteCASE <Informatik>Server (computing)Revision controlShift operatorWebsiteVideo game consoleDifferent (Kate Ryan album)Correspondence (mathematics)Expected valueNamespaceXML
Computer wormGroup actionRevision controlVideoconferencingReduction of orderRouter (computing)Electronic mailing listCartesian coordinate systemUniform resource locatorCodeConnectivity (graph theory)Disk read-and-write headBitLink (knot theory)Functional (mathematics)State of matterFormal languagePattern languageSoftware bugWeb browserCategory of beingType theoryWrapper (data mining)Social classRow (database)Latent heatFront and back endsMathematicsLevel (video gaming)Data structureSemiconductor memoryFunctional programmingComputer fileObject (grammar)Array data structure1 (number)Interactive televisionDependent and independent variablesDifferent (Kate Ryan album)NumberInternetworkingSoftware developerPoint (geometry)Library (computing)Software testingTerm (mathematics)CurveSpring (hydrology)Web pageSynchronizationoutputData storage deviceBoolean algebraSingle-precision floating-point formatSeries (mathematics)FeedbackMultiplication signDressing (medical)Presentation of a groupProcess (computing)Scripting languageSet (mathematics)System callWechselseitige InformationMereologyNormal (geometry)File formatMedical imagingFood energyComa BerenicesStaff (military)Integrated development environmentComputer-assisted translationXML
Different (Kate Ryan album)NumberConnectivity (graph theory)Electronic program guideConsistencyCartesian coordinate systemLibrary (computing)MassPerspective (visual)CodeExterior algebraJava appletPlanningSocial classCASE <Informatik>Process (computing)2 (number)Front and back ends
XML
Transcript: English(auto-generated)
I'm Jo. I'm super excited to be here. This is my first ever RailsConf, so that's great.
And I've come all the way from Melbourne in Australia. I wanted to tell you a story today, and the story starts in Melbourne. It starts with a group of four engineers. They started up a company called Culture Amp, and it's a company that I work for now. They built an online application using Ruby on Rails to run employee engagement surveys, and it provided real-time analysis of the results. Now, today, we have around
50 people working in our product team. We have ten development teams working on the product, and it's built with a whole bunch of technologies. We still have that Ruby on Rails monolith. We also have some Elm, some Elixir, and a whole heap of JavaScript. Back at the beginning, though, it was a whole other world, and I want to set the
scene a little bit so that this story makes sense. So I'm going to talk about the product and the market, where we started out. I'm going to talk about the front-end development scene and what was going on back then. I'm going to talk about the evolution that happened to us, that happened in the front-end development scene, sorry, and then the need to change, where we ended up. So, the product that we had
was offering analysis of survey responses, and it had two main areas of competition. The first one was consultants. They would run a survey, they would go away and spend a long time producing results in the form of PowerPoint documents or keynotes. And they looked beautiful, but they took a very long time. And then the other alternative
was things like Survey Monkey or Google Forms, and these would give you plenty of flexibility and real-time results, but it was very difficult to do anything with the data. You had to do a lot of the analysis yourself. So in this market, it wasn't very difficult for us to create a pretty groundbreaking front-end. We put in a bit of real-time analysis and some basic interactivity so that you could drill down into the results, and that was
enough to beat off these generic tools in the consultants' PowerPoints. Now, back then, the popular tools for front-end development were jQuery and Bootstrap. Now, it was 2011, we weren't talking about the dark ages here, so you could kind of be forgiven for thinking, well, why didn't they use something better? I mean, Backbone at that point was pretty mainstream.
Angular was gaining popularity. But when you think about jQuery, it was a game changer when it was first introduced. Its motto was jQuery is designed to change the way that you write JavaScript. It was designed to get rid of the JavaScript that people were writing then where they were putting it in line inside their HTML, so they gave you a way to move that JavaScript
into separate files. And its current strap line now is write less, do more. It's really unobtrusive. It's really easy to introduce it into Rails. In fact, it was included by default with Rails 3.1, which is where we started. It just makes things really easy. And if you look at Bootstrap, at this time, Twitter had just released their version 2 of Bootstrap. It was a
whole library of layout and grid components, so suddenly, column layouts were available to the masses. It was easy to add. We could drop it in from the CDN, or we could just put the file into the vendor folder in Rails. And like many startups, we really just wanted to have a reasonably nice UI, some smooth interactions for our users, and we wanted to get something to
mark it quickly. We didn't want to waste a lot of time playing around with JavaScript and CSS. These were back-end engineers, primarily. So what more do you want than these things that make life easy? So years passed by. We added a lot of new features. We added a lot of back-end features, permissions, data
analysis, these kind of tools, and the front-end really was something of a means to an end. It didn't get a lot of love. And Rails also makes it very easy to manipulate the vendor files, which is one of those things where just because you can does not mean that you should, because once you've changed one or two, trying to upgrade is a nightmare. So we just
had a load of spaghetti. And meanwhile, the JavaScript world was moving on. Some of the early benefits of jQuery, one of the things that had done really well was standardize across browsers. So if you wanted something that behaved the same in Internet Explorer as it did in, I was going to say Netscape there, wow, how old is that? And Chrome
and Firefox and so on, then it would give you that. It would let you have those behaviors. But as a result, the library had become really bloated, and browsers were really standardizing, so we didn't need this bloat anymore. Users, meanwhile, were starting to use JavaScript on their mobile and surf the web on their mobile devices, which meant they were demanding faster downloads. We had to build
smaller JavaScript libraries that did more. So JavaScript in this environment started to really become a first-class language. We had to think about how we structured it. We had to start adding in tests. We had frameworks like Jasmine and QUnit that were becoming mainstream. And meanwhile, we were back in this world where we had all this spaghetti code, and when we tried to
fix a bug, another one popped up somewhere else. I saw this video when I was preparing my presentation, I thought, this is exactly what it feels like when you're trying to fix one thing and it just bursts somewhere else. And this is how it ends. So we needed
a change. Now, what was happening at the time was React was emerging, so I'm going to talk a little bit about that. I want to talk about why we decided to go with React, how we evolved our asset pipeline to use it, and how we started to build the first components. Now, React was open sourced in 2013, and at
first glance, it really looks like another shiny JavaScript framework, right? There was a slide in the Elm talk earlier with a lot of different JavaScript frameworks. I don't know if some of you saw that, but people who are starting to learn JavaScript now are really overwhelmed by the number of choices that there are. So React is actually a little bit different. One of the things that really makes it stand out is
the idea of one-way data flow. Properties in React only flow down from the initial state through the components, and each individual component encapsulates its own props. It can't modify those props, can't modify the global state. The only way it can do that is through callbacks. React
components are a representation of the UI given the specific state that it's in right now. So we don't, within a React component, try and change the DOM the way jQuery does. Instead, it just renders a representation of the UI. And it uses this language called JSX. When you first come to React, it really kind of makes you want to vomit a little
bit because you're now mixing HTML in your JavaScript components, and you've just been learning that that's really bad. You should have them in templates, have them separate. But over time, you start to kind of realise that this is actually a much nicer way of working. So JSX looks a bit like this. It's an XML-like syntax, and it looks like HTML. It supports HTML-type components as well as
custom component tags. JSX allows us to pass properties down the component tree into the other React components. Now, React is also different because every time the state changes, every time we change the data that we're using to display the UI on the page, it re-renders the components.
It does this by maintaining a copy of memory of the DOM, and it calls this its virtual DOM. So every time the state changes, it can compare the current version of the DOM with the previous version, and so it knows which of the components need to be re-rendered, and then it will tell them to re-render themselves based on the new state. So by avoiding rendering the whole DOM, it means that
users don't necessarily have to re-scroll all the time, and it maintains the position of your cursor and so on. It also is a much more performant. If you compare this to jQuery, it turns out that trying to manipulate individual elements in the DOM is much slower than if you just redraw the thing. So if you imagine implementing a to-do list, you have a to-do, the user enters some
text, and then hits a button to add a new one. When you hit the button, you would call a callback which would update the overall state of the page and add the new to-do to it, and React would then know that that to-do list needs to re-render itself and include that new data. And one of the other benefits of React is
that it's backed by Facebook. It was open-sourced by Facebook, so it's got a big company backing it, building the tools, and investing in it. Unlike some of the other open-source tools, all of which are amazing and built by amazing community members, but having a big company behind it makes it a little bit more reliable and it's being maintained over the longer term.
One other thing I meant to mention is it's very easy to integrate one piece of React into the code base. So with things like Angular, you have to migrate an entire page over, but with React, what we were able to do is pick one small piece and then just put that component on the page alongside all of the other spaghetti JavaScript and leave that alone so that we could just have this one new component.
So when we thought about what JavaScript framework we should use, I know DHH talked yesterday about how really we should have gone and tried out 7 and done all our due diligence and really done the proper technical investigation, but surprise, surprise, we did not. But we did consider a few factors. First of all, our app is a B2B app, the users that
we have are primarily people working in HR, and they're usually accessing the app on a desktop computer. So we were able, we didn't have to worry about things like rendering on mobile phones, rendering on small screens, we could be quite targeted in the browsers that we had to build for. And we could restrict our support, so we actually support IE10, but we don't support anything less than
that, and we just support the latest versions of the other browsers, so we were pretty lucky in that we didn't have to worry about these older browsers. Another consideration was that we had hired somebody who was a React expert, so we had somebody in the team who could help us with this transition, and I think this is a really important aspect of the decision for us. We also didn't have to worry about SEO.
React is known for being able to do isometric JavaScript, so server-side rendering and so on, but for us, that wasn't something we needed to do, so given SEO wasn't a concern, it's actually quite difficult in Rails as well to get React to work that way, I don't know anyone who's done it, so not having to worry about that kind of opened up our choices.
Now one size doesn't fit all teams, I don't want to try and promote the idea that React is the framework you should all be using. It was right for us at the time. Now before we jumped into building React components, we needed to have a few things in place, and JavaScript had really moved on from the moldy old code we were trying to work with. We weren't even using any ES5 features, let alone ES6,
but out in the big wide world, there were all these amazing things that had been introduced with ES6. It was a really significant update, and again, it contributed to making JavaScript a much more first-class language to establishing it. So it fixed some issues, so block scoping and immutable constants were introduced with ES6. We also had some syntactic sugar, so arrow functions
were introduced, we had string interpolation, and we had the spread operator, all of which made our lives as JavaScript developers much easier. ES6 introduced classes, which some people love, some people hate, and it also introduced promises, so that was something that had for a long time been part of jQuery, but now it was part of the core
JavaScript code. And although ES6 would be a presentation in itself, if not more, so there's a really great repo by Luke Hoban that you should check out if you want to see more information on the features. Now, not all browsers support ES6 features, so we needed to use a transpiler, and Babel is one of the most popular ones. We had to figure out how to get it to run
in the asset pipeline, and what the transpiler would do was to use appropriate polyfills. When we started using ES6 features, you can tell it which browsers you want to target, and it would introduce the polyfills when they were needed and backport the new ES6 styles, like the arrow functions, to the older style JavaScript. And Babel supports enabling different feature sets,
so you can tell it what you want to use and what browsers you want to target. Now, the default Rails asset pipeline uses Sprockets. All of your JavaScript, your images, your CSS, is processed by Sprockets before it gets onto the client. And Sprockets uses require trees, so if you've written JavaScript files where you've required another file in it, Sprockets goes and gets the content from that other file,
puts it in as a bundle, and then that's the one that gets served to the client in production. When it creates these files, when you run your asset compilation, it puts a hash of the file contents into the file name. So every time you update and you re-release a new version, it's making sure that because the file name's changed,
it's preventing the browser from caching that old file for you. Now, Sprockets doesn't support transpilers like Babel. There are gems now to do this. It was going back a while when we were trying to introduce it. And so we looked at some of the tools that were being used in the JavaScript world, so Webpack and Browserify were the two most popular. And both of these are written in JavaScript, unlike Sprockets, which is obviously written in Ruby.
Now, we're in a JavaScript environment, processing JavaScript code, so it kind of makes sense to use a tool written in JavaScript to do it. So our first step to integrate Webpack into the Rails asset pipeline looked a bit like this. We had a gem that would run, we needed to run a node process in order to run Webpack.
It needed to run inside node. So we wrote a gem that would run a node satellite process alongside the Rails server, and the gem was called Ruby node task. We then had a separate gem called Webpack Rails, and what that would do would run a pre-built process within the node process so that we could incorporate these ES6 features in the JSX templates.
It would do all the transpiling within that step. Once Webpack had finished its processing, then Sprockets would do its processing and bundle these new Webpack-bundled files in with the old JavaScript, and then output them as normal. Now, this was pretty gnarly. I'm not necessarily recommending this as a good solution, but it worked at the time as a first step. It got us to the point where we could actually start using React.
But it was pretty soon we found we needed to update it. One of the biggest problems we had was that source maps, which are supported by Webpack, were not supported by Sprockets. So we weren't able to debug. When we saw an error, we would just get a long backtrace, and we couldn't figure out exactly where in our original files it was coming from.
So instead, what we started to do was, we would separate, have I got it on the right slide? Well, yeah, we tweaked the setup. So the files that were processed and bundled by Webpack were then no longer being included into these legacy files that were being bundled by Sprockets. So they were treated as a completely separate asset.
And the impact was then, we had two tags in the HAML. It wasn't too much of a big deal. We tried to avoid that, but ultimately this meant we could have source maps, we could have hot module reloading in development environments, and so that made it much easier. Now we needed a way to introduce our React components onto the page, and we were using HAML for our template language within Rails.
So we introduced this method that we could use in our HAML files. It's a top-level, it goes, sorry, it's a method that will add a top-level component into the page and passes state from the Ruby side. So we wanted to be able to pass props as a Ruby hash into this component. So we just output it with the content tag,
it's output as a div, and we used the data attributes. We put the component name inside one called data react component, and we put the hash inside React attributes. We then had a JavaScript method that would register all of the components we intended to use as top-level components in the page this way. And so we just registered them as the pages were loaded, and this created a map with the component name
and the actual component itself. And what it meant was that we could then mount them on the page load, and the mount components method looks at all the HTML in the page, and it picks up any nodes in the HTML that have this data react component attribute. It can then pick up the component name and the component props,
which have been loaded into these data attributes. And these get passed into the mount component method, so now it knows what the component is, it knows what its props are, and it knows the HTML node where we want it to appear on the page, and we pass all of that to react-dom.render, and that does all the hard work of outputting it there for us. So after the page is loaded, then our React code loads, and hey presto, we had React working in Rails.
So then we wanted to evolve a little bit, move on and do some more interesting stuff with it. We added some Jest tests. We added CSS modules. In the end, we lost sprockets. We introduced React route and Redux for some more complex code.
We introduced animations, and we also introduced immutable state. So when we first started using Jest, we wanted to have, with this beautiful clean code that we'd introduced, we really wanted to have unit tests from the ground up. Jest was created to work with React. Again, it's been created by Facebook.
It's quite different to other frameworks, like Jasmine and QUnit, where two we'd been using before. When we first introduced it, it was designed to mock everything by default. And this is really weird. It's a really kind of difficult learning curve and a difficult mindset change when you first start using a framework where everything is mocked. Ultimately, I think we got to the point
where we actually found that that made us write better code because you could only test the thing that was actually the thing you were trying to test, the one unit. So the test became much cleaner and just testing one individual thing. They have actually changed it now. So if you install Jest now,
the default is that it doesn't mock everything. They've written a blog post to explain their reasoning, but largely it's because so many people just found it such a mind shift and so different and difficult to get to grips with. Jest has also introduced, oh sorry, I want to talk about shallow rendering, and this was how we were able to test the output of React.
So given that it's rendering components, we had to figure out how we can actually test the output because usually it would render into the DOM. It would render into the browser DOM. And shallow rendering is part of the React test utilities library. What this does is rather than actually rendering the component into the browser DOM, it renders it as a kind of an object. So it just renders one level,
and you can then see, you can test that the outputs of that rendering are what you would expect. And we used it in combination with a package called React shallow test utils, and what that allowed us to do was to pick up nodes in the output and test whether the props were correct and whether they were appearing as we'd expected. And so this is what you would get from this shallow test utils.
It would go and find a node in the output, and it would have something like this, which is a normal JavaScript object if you output it to the console. So it's quite easy to just inspect all the different props in it. Now as I was about to say a minute ago, Jess more recently introduced snapshot testing. And so what snapshot testing allows you to do is that you can save the output of your component, and it saves it into a file
so that every time you're updating your component, you can just compare across versions. You can decide if there's a change in the output. Is that something I meant to have there? Or is it a bug that I've now introduced? What we've done with our components over time, we've abstracted a lot of the logic into very small files, very small JavaScript components. So whether if branches or case statements
or actual business logic in the components, we try and pull those out. So we try and adhere to the single responsibility principle and just have a lot of these very small modules just doing one thing well. And this has made testing of the logic of these much, much more straightforward. And if the component is just rendering a set of props, there's really very little value
in creating a lot of unit tests around it. So the test can be focused just on the modules that need it. Now we also introduced CSS modules. If this is something you haven't come across before, it's a small implementation of namespace class selectors for CSS. So rather than having a CSS class that's just global across your application,
you can have classes within a CSS module that only apply to the one module where it's included. And it was created by two prominent Australian front-end developers, Glenn Madden and Marc Dalglish. So for us, we were able to have, for each of our JavaScript files, a corresponding SAS file or a CSS file. So each JavaScript component had ownership
over its own CSS styles, and it let us avoid the hell of CSS class name clashes when we were using these components in various places on the site. Now CSS modules uses a tool called PostCSS, and what that allows us to do is to process it with our JavaScript compilers, with JavaScript plugins, sorry.
So we could use Webpack to process the CSS modules and output them as JavaScript. And then within the JavaScript file, you can just use them like a JavaScript object. The next thing that we wanted to do was to try and get rid of sprockets. We were really starting to feel the pain of working with sprockets together with Webpack in our development environment especially.
We wanted originally to try and do things the Rails way, but we wanted to avoid a change that felt too big at the time. But people were getting used to Webpack now, and we were also finding that if it got stuck compiling something, we had to restart the whole Rails server because of this node satellite process that we'd introduced.
And the code base was growing in complexity, so this was happening more and more often. It was a real pain. And we still couldn't support source maps in production because ultimately, the code was still getting compiled by sprockets. So the solution was to entirely replace sprockets with Webpack. The one problem that we had left to resolve here was that sprockets does this, as I mentioned,
it renames the files with this hash in the file name. So we had to find a way of setting Webpack up to do that same thing so that our production files weren't being cached by the browsers. And the way sprockets does this is that it maintains a manifest file and it maps the original name of the file that's gonna be compiled against the name
with the hash in it. And then when you load your files in development, it's gonna get them from the local machine. When you load them in production, it's gonna go and get the file name with the hash. So we used an NPM package called Webpack Manifest plugin, I think. And that does the job of creating this manifest file for Webpack and having the same functionality as sprockets was doing,
so that then we didn't need sprockets anymore and Webpack serve all of our files in production. Then we wanted to add single page transitions. We had all this fancy code, we had all these nice new components in React. We wanted to use them to create a better user experience. And this meant that we had to introduce Redux. We needed something more complicated
to manage the overall state. So at a high level, we also introduced React Router. At a high level, Redux is a state management library and it was heavily influenced by Flux and by Elm in its design. So the state of the app is stored in a single global state, a single global store. And the only way that you can make changes to this store from a component is by emitting actions.
And actions will contain a payload. So to go back to the todo list example, if you emit an add action for a todo, it will contain the details of the todo. This in turn calls a method in the reducer which knows how to produce an updated version of the current state. We don't change the state,
we don't actually edit the object itself, we create a whole new version and that gets sent back to the store. This then updates all the components. React looks at its virtual DOM, decides which ones need to change and passes the updated state down to them. And React Router is a JavaScript routing library which allows the URL to stay in sync
with what's on the page. There's a newer version of it, version four, and it's very, very different to the point where there's a lot of stories on the internet about people who've tried to upgrade. It matches the components in the URL to the components on the page so that they can decide based on the URL components which pieces to display.
We're still using the old version, we haven't managed to upgrade yet because it's such a big change and they are maintaining the old version indefinitely. Although I think if you're starting a new application now it's probably better to go with the new one. Now in our world we wanted to implement actions that could be called in response to a user interaction like a click. So you click a link to view data for a specific question.
And you can have actions that trigger actions. So the first thing that we did was to trigger an action to say the URL has changed. This triggers a second action which checks if you require new data to be loaded which if you're gonna view a different question or a different page, nine times out of 10 you do unless it's the current one.
So this would change the URL and this would trigger a new action which would go and trigger an Ajax request. It uses fetch which returns a promise and then when the Ajax request returns it resolves the promise. This triggers a new action again which updates the data or tells us that the data's been updated.
And finally this goes to the reducer which processes the data. The components are then re-rendered with the new version of the data. Now this is a very simplified overview of how React Router and Redux are working in our application. I really recommend if it's something you want to learn more about there's some awesome videos on Egghead and a lot of them are free
and they have a couple of series on Redux and on React Router so that's the best place to go. We also introduced some animation with our single page transitions. We needed some kind of feedback in the UI to show the user that the page was changing. The usual way we do this is with animations and so we found this library called React Motion
and it did things like shifting the bars from the old value to the new value when the data was changing. It's an NPM package. It supports a thing called springs which is a way of animating things in the UI but unlike timed animations one of the nice things about springs is that they're interruptible so you get these nice realistic kind of animation curves
but if you have to stop halfway through it can then jump from wherever it is to the next place which is better than the usual timed animations that you would have in CSS. Some issues that we ran into well when we tried to render PDFs we had to make sure that the animations were not running then and in our tests as well we had to find ways around it because we didn't want to check the value
of the components with the animation half run. Now, sorry, Redux is based on the principle of immutable state and we wanted to try and use that more across our application. So this is one of the libraries that we introduced very early on, ImmutableJS which has helped us to think in terms of immutable data
and in terms of not changing something in place but returning a new version of it. So it provides a number of different objects that we used map and list were the ones we used the most and in normal JavaScript if you edit an object or an array it just edits the object in place but what ImmutableJS does is that it will return you a new collection
with the changes that you want without changing that original object. So it's protecting you against a lot of subtle bugs that can come up in your JavaScript files. And it's also highly optimized if you try to implement this on your own and you probably end up in a state where you're running out of memory but it uses a lot of shared structures underneath. So it's optimized for performance
and you can use this a lot more safely in your code. And this is an example of what it would look like if you changed a map, an immutable map. You can see that the original map hasn't changed. We also used record types from ImmutableJS and we used these to define specific types or data structures that we could pass between our components.
Now there's a move towards more strict type checking in the JavaScript community in general and newer front-end languages like Elm already have static types built in. React allows us to define props for each of our components and so what we were able to do was define types of these records that would have specific properties
that we knew should be present and we created this strong record class as a wrapper around the ImmutableJS record so that it would present us more warnings and we could really check, does it have the properties, does it not have any that it shouldn't have? And then when you pass the prop types to React, we could do more checking to make sure whether something was required or not and what props it is expected to have
and in the development environment, it would give you warnings in the browser so you could see if you weren't passing the right things. So again, this allows us to identify subtle bugs much more easily. So what have we learned on this journey? We've learned a lot for a start.
It's helped us to introduce a lot of new patterns and better ways of approaching and structuring our code. React is inspired from functional programming principles so it's something we also see happening in the Ruby and Rails world. There's more kind of functional programming ideas coming into that so we had a bit of a head start there and it really makes you think slightly differently about how you structure your code in any language.
For example, state never being mutated, creating a new object to store in state and passing things through functions to get a new value back instead of modifying them and we've found that we end up creating cleaner code. It's easier to test because you're just testing inputs and outputs instead of having to mock behaviors. So does this story have a happy ever after?
Well, legacy JavaScript is still a thing. We haven't got rid of it yet. We now have a massive library of React components and we haven't given an awful lot of thought so far to the reusability of those components so that's starting to be an issue. We have a number of different components that do very similar things and we do still have a lack of overall consistency
in our CSS. Where we're using CSS modules, it's awesome but we also have a lot of global styles still and I never knew there were so many different ways you could make a button appear but I think we've got about 15, so. So this story has an epilogue. We are moving towards more of a shared component library,
something that a lot of companies are now doing is implementing a living style guide so people like Envato, Lonely Planet, Airbnb and Atlassian are all companies that have published their style guides. In Lonely Planet's case, they have a gem that they use and Atlassian, they have Atlassian UI which is a Java package that people can actually use
to use their components and styles. We're also experimenting with alternatives like Elm. We've got about a quarter of our application now which has an Elm UI integrated into the React one and we are starting up a team that's gonna own this front-end experience and try and replace all of those 15 different buttons with at least one or maybe two.
And I think since we started our journey, we've really learned a lot. Our front-end code has moved on and the world around us continues to move on and evolve so it's still not perfect. The biggest difference though is that we now treat our code much more as a first-class citizen on the front end, not just the spaghetti mess means to an end that it was before.
And we hear back from our users that they can really tell the difference because of that. So I guess whatever you're doing, wherever in your journey you are, whatever library you choose to use, I hope you may have got something out of our perspective and our experience with React on Rails. Thank you.