Using React with Phoenix

I’ve been recently building api’s using Elixir and Phoenix as well as some side projects. One of the project uses a very complex application written with React and so here is how you can integrate a react application with Phoenix (Without using webpack).

create a new Phoenix proect

First lets create a new Phoenix project. Assuming you already have Phoenix/elixir installed, run:

  • mix phoenix.new phoenixReact

Answer yes to install any dependencies. then:

  • cd phoenixReact
  • mix ecto.create
  • mix phx.server

You might see mix phoenix.server being used, but thats now depricated. Once complete you new project can be seen at localhost port 4000.

now lets install a few npm dependencies.

  • npm i --save-dev react react-dom

no lets add some code to out app.js (inside web/static)

import React, { Component } from 'react'
import reactDom from 'react-dom'

const App = () => (<h2>Hello from React</h2>);

reactDom.render(<App />, document.getElementById('app'));

Stright away you’ll get an error from Phoenix as it doesnt understand React/JSX. What we need to do is use babel to traspile the code first.

Adding babel react presets

First we need the babel react preset, remember that Phoenix already comes with babel as part of the Brunch configuration, so we only need add the preset and es2015 preset.

  • npm i --save-dev babel-preset-react babel-preset-es2015

Next we need to update the brunch.config.js file with our new preset:

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

You code will now transpile perfectly by Phoenix/Brunch without the need to add a dedicated javascript build tool (like webpack).

just add <div id='app'></div> to your templates/page/index page to see the react output.

Adding react-router

Next our app needs some routing, so lets add that:

  • npm i --save-dev react-router-dom

Lets update our app.js with some routes

import React, { Component } from 'react'
import { BrowserRouter, Route, Link } from 'react-router-dom'
import reactDom from 'react-dom'

const Home = () => (<h2>Home Page</h2>);
const About = () => (<h2>About Page</h2>);

const Routes = () => (
    <BrowserRouter>
        <div>
            <ul>
                <li><Link to="/">Home</Link></li>
                <li><Link to="/about">About</Link></li>
            </ul>

            <hr/>
            <section>
                <Route exact path="/" component={Home}/>
                <Route path="/about" component={About}/>
            </section>
        </div>
    </BrowserRouter>
);

reactDom.render(<Routes />, document.getElementById('app');

We now have a simple react app with routing all compiled on change by Phoenix. We can now build the app up with components and redux and use phoenix for our api and other features.