Setting up a Basic React.js Front End for your Rails Server
Tags: rails, beginners, javascript, react
Published: 2020-09-26 15:27:19

So if you've been following along you have a basic Rails server that is returning JSON.

Now let's hook it up to a basic React.js front end.
___
We're going to use the react-rails gem to hook up React with Rails. So let's add it to our `Gemfile`. Just add the line `gem 'react-rails'` in there, and then we need to run several commands in the terminal.
```
bundle install
rails webpacker:install
rails webpacker:install:react
rails generate react:install
```
And we have React.js hooked up in our Rails sever. Now we need to write our React.js components to talk to the back end.
___
But before we do that we have a couple more things to take care of in our Rails server. We're going to be serving up a static page with our React.js code so we need to tell Rails how to show that.

So, let's generate a home controller with `rails g controller Home`. Don't worry this controller is going to be incredibly simple. So first, let's add a route for it. Go ahead and add `root 'home#index'` to your `config/routes.rb`. This will route your root directory to our home controller, which is just going to show our React.js page.

So let's set up our `app/controllers/home_controller.rb` now.
```ruby
class HomeController < ApplicationController
  def index
  end
end
```
That's it. In this case, all we want to do is say that it exists. That way Rails will render the view. Let's set that up now as well. Create a `app/views/home/index.html.erb`.
```ruby
<%= react_component 'app' %>
```
That's it. That's the whole file.

Let's grab axios real fast so our front end can talk to our back end. So go ahead and run `yarn add axios`.

And now we can actually start writing React.js and we just want to name our component the same as the one we called in our index.html.erb, because that's what's going to show up. So create a `app/javascript/components/app.jsx` file. This is where Rails is going to look for our components.

So let's setup up a very basic React.js component.
```javascript
import React, { useState, useEffect } from 'react';
import axios from 'axios';

const app = () => {
  const [dogState, setDogState] = useState([]);

  useEffect(() => {
    axios({
      method: 'GET',
      url: '/dogs'
    })
    .then(({data}) => {
      setDogState(data);
    })
  }, []);

  return (
    <div>
      <h1>These are our dogs</h1>
      {dogState.map((dog, i)=>(
        <div key={dog.id}>
          <p>{dog.name} age: {dog.age}</p>
        </div>
      ))}
    </div>
  )
}
export default app;
```
Here we set up the starting dog state with an axios call in our useEffect. And then we just display a list of those dogs. But we want to do more than that. Let's add a form to add a new dog to the list as well!

Go ahead and add this inside the outermost div tag in our return statement.
```javascript
<form>
  <label>Name:
    <input onChange={changeHandler} type="text" id="name" value={dogInfo.name}/>
  </label>
  <label>Age:
    <input onChange={changeHandler} type="number" id="age" value={dogInfo.age}/>
  </label>
  <button onClick={addDog}>Add Dog</button>
</form>
```
This is a very basic form, but it's looking for some stuff we don't have yet. Notable a changeHandler function, an addDog function, and a new state to manage the form.

First let's add our new state that will manage the form and give it some initial values.
```javascript
const [dogInfo, setDogInfo] = useState({name: '', age: 0});
```
Now let's set up our changeHandler function that will update the dogInfo state whenever you change one of the form inputs.
```javascript
const changeHandler = ({target}) => {
  setDogInfo((prev) => ({...prev, [target.id]:target.value}));
}
```
And now we will also add the addDog function that calls our API route.
```javascript
const addDog = (e) => {
  e.preventDefault();
  axios({
    method: 'POST',
    url: '/dogs',
    data: dogInfo
  })
  .then(({data}) => {
    setDogState((prev) => {
      const newList = [...prev];
      newList.push(data);
      return newList;
    });
  })
};
```
We call our Rails API exactly how we would call any other backend. It's easy peasy. Then we update our dog state with the new information. Notice how we're returning a new object so React knows to update the dom.

So now that we can add a dog, we need a way to remove and edit a dog. So let's add those buttons to our `map`. So just update it to look like this.
```javascript
{dogState.map((dog, i)=>(
  <div key={dog.id}>
    <p>{dog.name} age: {dog.age}</p>
    <button onClick={()=>removeDog(dog.id, i)}>Remove</button>
    <button onClick={()=>updateDog(dog.id, i)}>Update</button>
  </div>
))}
```
We'll need to add those functions to our component as well. So let's add them.
```javascript
const removeDog = (id, i) => {
  axios({
    method: 'DELETE',
    url: `/dogs/${id}`
  })
  .then(() => {
    setDogState((prev) => {
      const newList = [...prev]
      newList.splice(i, 1);
      return newList;
    });
  })
}

const updateDog = (id, i) => {
  axios({
    method: 'PUT',
    url: `/dogs/${id}`,
    data: dogInfo
  })
  .then(({data}) => {
    setDogState((prev) => {
      const newList = [...prev];
      newList[i] = data;
      return newList;
    })
  })
}
```
These two look very similar to the addDog function, because they are. We just make the relevant axios call and then update the state on the front end with the response that we get back.

I've omitted all my error checks and this is a very bare bones component. But the important thing to observe here is that this is just a regular React.js component.
___
And that's it. This was a very basic walk through of how to get a CRUD Rails server up and running with a React.js front end that talks to it. Just remember that we're working with simplified examples here, but hopefully this gave you the courage to try it out on your own!