Full-Stack React With Phoenix (Chapter 4 | Implementing React)

Michael Mangialardi
Coding Artist
Published in
5 min readJul 26, 2017

Table of Contents

Chapter 1 | Why Bother?
Chapter 2 | Learning the Basics of Elixir
Chapter 3 | Introduction to Phoenix

Scope of This Chapter

So far, I’ve been able to keep these chapters relatively short (Well…I guess that depends on your perspective but I’m used to 8–20 hours of time to write my chapters). You may be expecting this chapter to break that trend. However, a generated Phoenix application only needs a few tweaks in order to run a React frontend. In this chapter, we will render a very simple React frontend and you will know how to add setup a React frontend to any Phoenix project.

Setting Up a React Frontend

First things first, let’s create a new Phoenix project called helloreact:

mix phoenix.new helloreact
cd hello-react

Open up this project in a code editor and recall that there’s a package.json file in the root for our frontend configuration:

Therefore, we can go on ahead and install our React dependencies with npm:

npm install --save react react-dom babel-preset-react

Once this installs, we just need to apply Babel to preprocess our code which needs to happen in brunch-config.js. Recall, Brunch is an alternative to Webpack for asset managing. However, apply the Babel preset for React will be very similar:

plugins: {
babel: {
presets: ["es2015", "react"],
// Do not use ES6 compiler in vendor code
ignore: [/web\/static\/vendor/]
}
},

In addition, we need to add a whitelist in under the npm options in this file so that it is clear that we are going to use react and react-dom:

npm: {
enabled: true,
whitelist: ["phoenix", "phoenix_html", "react", "react-dom"]
}

We could manually build our frontend using brunch build, however, this will run when we fire up our server.

For now, let’s go ahead and add a very simple React app.

First, we can create the target for our app in the index.html.eex template (delete everything else):

<div id="hello-react"></div>

Note that the index.html.eex template is nested within app.html.eex. The app template contains a pre-populated header which we can remove:

<header class="header">
<nav role="navigation">
<ul class="nav nav-pills pull-right">
<li><a href="http://www.phoenixframework.org/docs">Get Started</a></li>
</ul>
</nav>
<span class="logo"></span>
</header>
^^^ delete this

Now, our React app with be targeted to our index.html.eex template and ultimately nested within app.html.eex and display in our browser.

Next, let’s define the actual React app.

Our React application will go in app.js found in the following path:

web/static/js/app.js

The js folder will be like the root of your React project where you can create your project directory. For example:

-- js
-- components
-- scenes
- app.js
- index.html
//etc...

We won’t create a project directory in this chapter. Let’s simply add the following into app.js:

import "phoenix_html"import React from "react"
import ReactDOM from "react-dom"
class HelloReact extends React.Component {
render() {
return (<h1>Hello React!</h1>)
}
}
ReactDOM.render(
<HelloReact/>,
document.getElementById("hello-react")
)

We can now run mix phoenix.server and see our React application running on http://localhost:4000/:

Woot woot! We are all set to crank out a React application as we traditionally would.

Implementing React Router

Explanation

The only other thing that I want to walk through is setting up React Router. This will work exactly like any traditional React application. However, I want to clear up any confusion between our Phoenix router and our React Router.

As we looked at in the previous chapter, we can use the Phoenix router to ultimately control templates that are rendered on different paths.

Currently, the / path calls a function called index in a controller called PageController:

get "/", PageController, :index

This controller invokes the rendering of the index.html.eex template (with a view specified to make this render).

The index.html.eex file contains the target of our React application.

Our React application is a single page application. Meaning, only a single page has to be loaded by the server (as we have it right now).

The React router is used to update the current URL path shown in the browser for different views within our single page React application.

For example:

class App extends React.Component {
render() {
return (
<Router>
<div>
<Route exact path="/" component={Home}/>
<Route path="/login" component={Login}/>
</div>
</Router>
)
}
}

In the example above, the / path will render a component called Home. The /login path would render a component called Login. The Login component would cause the URL in the browser to look like this:

http://localhost:4000/login

Despite the URL being updated, nothing has changed with the server-side routing. The / path is rendering our entire React application. Because React Router specifies <Route exact path=”/” component={Home}/> in the example above, http://localhost:4000/ will display a React component called Home.

Implementation

To better retain this information, let’s implement React Router in our current Phoenix application that has a React frontend.

First, we install react-router-dom at the root of our Phoenix project:

npm install --save react-router-dom

Then, let’s import a Router, Route, and Link into our React application found in app.js:

import { BrowserRouter as Router, Route, Link } from 'react-router-dom'

Let’s also update our render to match the following:

render() {
return (
<Router>
<div>
<Route exact path="/" component={Home}/>
<Route path="/login" component={Login}/>
</div>
</Router>
)
}

Usually, we would create the two components in separate files. For now, let’s just add the following in app.js above the ReactDOM.render stuff:

class Home extends React.Component {
render() {
return (
<div>
<h1>Hello React!</h1>
<Link to="/login">Login</Link>
</div>
)
}
}
class Login extends React.Component {
render() {
return (
<div>
<h1>Hello Boring Login Page!</h1>
<Link to="/">Home</Link>
</div>
)
}
}

Go to http://localhost:4000/ and we should see this in action:

Woohoo! We are routing different views within our React application on the client-side even though only a single route is defined to render this single page React application on the server-side.

Final Code

Available via GitHub.

Concluding Thoughts

As you can see, creating a React frontend within a Phoenix project is quite simple. Pardon the boring examples so far, we are about to crank up the power of Phoenix and React by introducing data from a PostgreSQL database.

Chapter 5

Chapter 5 is now available.

Sign Up for Notifications

Get notified when each chapter is released.

Cheers,
Mike Mangialardi
Founder of Coding Artist

--

--