From Rails to React; A Fullstack Conversation

Ruby on Rails developer with no React experience. My front ends are currently 100% html.erb (plus AJAX / javascript for the fancy bits).
Ruby on Rails + React Developer
Follow this Taaalk

3 followers

1,428 views

Joshua Summers
17:35, 19 Jun 20
Hello Aidan ūüĎč and thank you for Taaalking with me
So this is what I know about RoR right now... and it's also the beginning of my first point of React confusion.
In a controller there is function for a certain type of page - e.g. the 'index' page. Which provides data to be passed to the view (an index.html.erb file) in the form of an instance variable.
class DogsController < ApplicationController
  def index
    @dogs = Dog.all
  end
end
Which would have an index.html.erb file of:
<h1>All the Dogs!</h1>

<% @dogs.each do |dog| %>
  <h3><%= dog.name %></h3>
  <p><%= dog.description %></p>
<% end %>
And all my doggy data would pour out onto the index page.
First things first, if I'm working with React, a frontend framework which isn't within Rails, am I still sending data to the front end using an instance variable (i.e. @dogs)?
Aidan Damerell
20:22, 20 Jun 20
Hey Josh, first off thanks for starting this conversation , It'll be interesting to know your thoughts on the subject!
So the first important thing to remember about React - it's just a front end library. A library which exists (for the purpose of this explanation) in the browser. This means that you free to handle how the data gets to the front end in whatever way you want whether that be by using API calls within React, passing props to components or storing them within the front end package itself.
If we image how exactly Rails handles your request;
1. You make a request to /dogs
2. Rails says hey, I've got a route that matches that, it's #DogController#index, I'll run that function and render the template dogs/index.html.erb
3. Rails will parse the ERB file and run the logic within (such as passing @dogs to a enumerator)
4. Rails will then return you the FULL HTML page including all the dogs in their header tags.
Easy right? Now lets image we want to build a React app to do this. In our React app we would do a similar thing, we would request all the dogs from /dogs, which we would recieve from the Rails app and we would render them out. The important difference is where and when the rendering happens. In our Rails example the index page is technically all rendered (convered to HTML on the server), whereas in React, we pass the values to React which will in turn convert that to HTML on the client side.
To answer you last question, let's assume your using the react-rails gem and we aren't using a React SPA with react-router or something similar. Imagine we want to convert our existing Rails index.html.erb to a React app, we would write the component and then use the "react_component" method in the ERB template to load that React. Remember that React is just JS and a component is just a function which will output HTML. Using the react_component function we can actually pass data into the component which will mean we could do the exact same thing as in your example. Here's an example:
// Doggindex.jsx
import React from 'react'

const DoggieIndex = ({dogs}) => {
  return(
    <React.Fragment>
      <h1>All Dogs</h1>
      { dogs.map(dog => <h3>{dog.name}</h3>) }
    </React.Fragment>
  )
}
export default DoggieIndex
// app/views/dogs/index.html.erb
<%= react_component 'DoggieIndex', { dogs: @dogs } %>
Joshua Summers
09:37, 21 Jun 20
whereas in React, we pass the values to React which will in turn convert that to HTML on the client side
Ahhhhaaaaaaaaa ūüí°. This I did not know.¬†
So before we get further into the technical details of how React works, why would I want to generate my HTML on the client side rather than the server side?
Aidan Damerell
12:02, 21 Jun 20
Well that's a good question! I think I should point out that server-side rendering (SSR) is completely possible in React but we'll leave that for now.
There are a number of benefits to client-side rendering, one of which is speed. Imagine with your ERB setup, every time a user visits a new page the server has to send over ALL the data again. This includes all the "extra" which isn't actually part of the specific data we need.
Imagine we have a similar setup to the dog index page, every time you want to view this page using the ERB setup, we would have to send the entire HTML page, whereas with React we could just send the array of dogs.
Another good reason for rendering the HTML on the client side (using React) is we have easy and direct access to the HTML elements as we built them! Imagine you wanted to use jQuery to perform some action on an element on your page. Your browser would recieve the page, render the HTML and THEN your jQuery function would run thus causing the browser to re-render the page. Whereas in React, we cant simply perform the mutation before we render the content.
Joshua Summers
13:17, 22 Jun 20 (edit: 13:32, 22 Jun 20)
Mmmhhhhmmm ok. That does make sense. I've always heard people discuss speed and React but never understood it until now. 
So continuing with your Doggindex.jsx example being served using the "<%= react_component 'DoggieIndex', { dogs: @dogs } %>". Where does this file live in my Ruby application? For example, is it just another file in the app/views/dogs directory?
And I suppose that my file has to make it from my Ruby application stored on a server, to the client making the request, and then do the rendering... is that correct? [It feels like that might cut down on the speed advantage, but maybe I'm wrong...?]
Aidan Damerell
15:01, 22 Jun 20
So in that example we're using the helper `react_component` from the react-rails gem. All that does is look in the the /app/javascript/components directory for a file which matches that name (I should add, this is Rails 6).
So our example using the DoggieIndex.jsx would not result in a massive speed increase. The speed increase and percieved speed increase comes from using what's known as SPAs. This is where the entire front end of your application is in escence a single page. react-router is a good example of a library for building SPAs. SPAs are quick because the entire app is loaded to the client's browser upon first load. So the only data which needs to be transfered is the actual information you want to view, in our example a list of dogs.
So when the client browses through our application, the UI would appear to load instantly and in the background fetch the information.
React also allows us to build PWA (progressive web applications) which mean that actually, we can store the entire application on the client side in a cache. This makes the app lightning fast.
Joshua Summers
14:02, 23 Jun 20
Right, ok that is making even more sense. So when my whole front end had been downloaded, all I'm doing is sending data back and forth to the server? That does sound faster.
So will stick with the react-rails gem world for a while, as it seems like a good way transition. Firstly, what would be rational for using a .jsx file/a react component vs sticking everything into a .erb file like I'm currently doing? (And what is difference between a .jsx file vs. a .js file?)
Aidan Damerell
14:08, 23 Jun 20
One of the great features we can really draw on in React is compartmentalisation. Similar in how Rails partials work, we can reuse our code elsewhere in our application by simply importing it. I don't think putting all your React code into a ERB file would work at all for this, as Webpack would be completely unaware of it.
So, JS vs JSX - They're identical. JSX is actually the format which the Facebook team came up with to include HTML inside of a JS file. The different extensions will have no impact on your code, but I personally prefer JSX as it signifies that his include JSX code (not just Javascript).
Joshua Summers
14:45, 23 Jun 20 (edit: 14:52, 23 Jun 20)
I don't think putting all your React code into a ERB file would work at all for this, as Webpack would be completely unaware of it.
I think we're slightly talking about different things here, I was talking less about this, and more about keeping everything in standard html.erb format (so using zero React). I guess what I'm trying to get at is why would anyone ever use the react-rails gem?
Before I started this Taaalk, I thought React was a binary choice, either I use it for the front end of my project or I don't - now I feel like there are decisions to be made, I can use it for some areas and not for others. In terms of:
One of the great features we can really draw on in React is compartmentalisation. Similar in how Rails partials work, we can reuse our code elsewhere in our application by simply importing it.
As you say, Rails partials can do this, so I'm unsure how to think about when to integrate React into my Rails project. I'm imagining I'm building a Rails project and I want to be able to think to myself "ah-haaaaaa" I should use a React component for this.
Aidan Damerell
14:54, 23 Jun 20
I think we're slightly talking about different things here, I was talking less about this, and more about keeping everything in standard html.erb format (so using zero React). I guess what I'm trying to get at is why would anyone ever use the react-rails gem?
Well we would want to use React for it's speed, simple access to the DOM and great state system.
Rails partials do definitely allow us to re use code and components but we are still using ERB in that setup. React allows us not only to have fast and responsive apps, it also allows us to easily track "state". I wont try and explain state myself as it's a complex topic but the jist of it is; you have a defined "state", when the state of a component changes, the component will re-render. This means that we can easily handle things like input fields, themes and layouts and have them propogate through our app with little manual to no manual coding.
You're unlikely to find a project and say "this will be great in React compared to a standard ERB layout". All React does is allow us to more easily create responsive front ends.
Joshua Summers
21:28, 24 Jun 20
Ok cool :)
Would it be ok to give a few direct examples of when you have made the decision to use React in that way?
I am definitely building more clarity, but I feel like I still wouldn't be sure about how the thought process would go in an actual project, and I feel a real world example or two would get me there.
Aidan Damerell
08:12, 25 Jun 20
So personally I would say I would always use React. Combining the two just leads to complexity compared to using one or the other. To add a little more fun into it, how about you provide me with some HTML + jQuery and I'll convert that into React and explain the benefits?
Joshua Summers
09:37, 25 Jun 20
OK, sounds good.
Let's start with something simple:
<p>
  You should 
  <%= link_to "start your own Taaalk", new_tlk_path, class: "link-txt" %>
  today!
</p>
Aidan Damerell
09:50, 25 Jun 20
So I've taken that and built on it a little.
import React from 'react'
import {Grid} from 'somewhere'

const LinkToParagraph = ({topText, bottomText, linkText, location}) => (
  <p>
    {topText}
    <a href={location} className='link-txt'>{linkText}</a>
    {bottomText}
  </p>
)

const MyApp = () => {
  return(
    <Grid>
      {/* the rest of the app*/}
      <LinkToParagraph topText = 'You should' linkText = 'start your own Taaalk' location = '/start-conversation' bottomText = 'today!' />
      <LinkToParagraph topText = 'You should' linkText = 'do something else' location = '/something' bottomText = 'today!' />
    </Grid>
    )
}

export default MyApp
Notice how easily we can re-use that LinkToParagraph for the second link? We would then use something like "react_component("MyApp")" render that to our page.
You may be thinking "hey, that's a lot more code than my original", dont forget the "MyApp" is just to demonstrate how we could use the component. Think of "MyApp" as the generic wrapper around everything in your application.
What are your thoughts on that?
How about something with a little bit of JS logic in it for the next one? That's where React can shine!
Joshua Summers
22:55, 26 Jun 20 (edit: 22:56, 26 Jun 20)
Ok, JS coming soon... there's actually been a block of JS in my 'Saved Draft' message since we first started Taaalking.
Ok, so let me break down the code you wrote (this might take a few back and forths, but it will mean we will be able to get much faster as we go on).
import React from 'react'
This might be stupid, but why and what is this? My guess is that 'react' is a bunch of core React JS that gives all the rest of the JS code "powers" (is React written in JS?). This needs to be brought into every component because one thing that makes React special is that when you load a component you load it in isolation? So it has to have all of the supporting stuff come with it?
And now onto the first bit that leaves me totally lost:
import {Grid} from 'somewhere'
What is about? What is Grid? Why is it needed? And why am I importing it?
Aidan Damerell
19:32, 28 Jun 20
So remember, React is just a library, here we're simply importing the exported function from the 'react' library. Think of import in a similar way to 'require' in Ruby.
Yes, React is written in JS, it's actually a very small library considering what it does (5.3kb)!
So any file that uses JSX will have to import React as this is something unique to the React library, and the library actually breaks down the JSX into standard javascript.
Ah, I thought you might ask about Grid! I was just using this as an example, such as you might find in Semantic UI or Material UI. React can render a single component or an array of components, so we must ensure that our 'MyApp' component returns a single component, a simple way of doing this is to wrap everything in something like a 'Grid'
Joshua Summers
21:29, 29 Jun 20
Ok so here is my remaining 'Grid' confusion.
When we have:
<Grid>
   {/* the rest of the app*/}
   <LinkToParagraph topText = 'You should' linkText = 'start your own Taaalk' location = '/start-conversation' bottomText = 'today!' />
   <LinkToParagraph topText = 'You should' linkText = 'do something else' location = '/something' bottomText = 'today!' />
</Grid>
I understand that we will then be inserting the <Grid>...</Grid> component (or block of HTML?) into our application.
But if this is simply a block to be inserted, why are we not doing:
<div>
   {/* the rest of the app*/}
   <LinkToParagraph topText = 'You should' linkText = 'start your own Taaalk' location = '/start-conversation' bottomText = 'today!' />
   <LinkToParagraph topText = 'You should' linkText = 'do something else' location = '/something' bottomText = 'today!' />
</div>
Or even:
<foo>
   {/* the rest of the app*/}
   <LinkToParagraph topText = 'You should' linkText = 'start your own Taaalk' location = '/start-conversation' bottomText = 'today!' />
   <LinkToParagraph topText = 'You should' linkText = 'do something else' location = '/something' bottomText = 'today!' />
</foo>
Why do we need an:
import {Grid} from 'somewhere'
?
If we are inserting an arbitrary block, why do we need to import anything at all? Or is 'Grid' a thing with special properties that are good for adding components to the DOM?
Aidan Damerell
09:57, 07 Jul 20
You're 100% right, there is no reason to use Grid (other than for layout). You could definitely use a div tag, or even React.Fragment which is React's way of providing a surrounding tag.
Grid is something you'll find in SemanticUI and MaterialUI. Take a look at the libraries and the use case for this will be pretty obvious.
Joshua Summers
11:06, 07 Jul 20
Ok, so when you are importing 'Grid' you are importing a front end framework?
As in you could have simply written:
import React from 'react'

const LinkToParagraph = ({topText, bottomText, linkText, location}) => (
  <p>
    {topText}
    <a href={location} className='link-txt'>{linkText}</a>
    {bottomText}
  </p>
)

const MyApp = () => {
  return(
    <div>
      {/* the rest of the app*/}
      <LinkToParagraph topText = 'You should' linkText = 'start your own Taaalk' location = '/start-conversation' bottomText = 'today!' />
      <LinkToParagraph topText = 'You should' linkText = 'do something else' location = '/something' bottomText = 'today!' />
    </div>
    )
}

export default MyApp
And you would have achieved a similar result?
Follow this Taaalk

3 followers

1,428 views

Start your own Taaalk, leave your details or meet someone to Taaalk with.