Using React and Typescript in Phoenix

So you’ve been working on LiveView and you totally fell in love with it. You now think “holy crap, I’m never touching javascript ever again!”, and I’m 100% with you. But sometimes, you just need react.

In this article we’ll go over how to setup React with Phoenix using esbuild without using a third party mix package.

Setting up react

The first thing you need to do is install the rect packages:

cd assets
npm i react react-dom

Now create a test comopnent:

// assets/js/components/Test.jsx
import React from 'react';

export default function TestComponent() {
  return {
    <div>
      <h1 style={{fontSize: '4em'}}>This a react component</h1>
    </div>
  }
}

I like to then create a separate .jsx file with a function too render the react app into a DOM element. You could do this inside the assets/js/app.js that comes built into Phoenix, but I like to keep that file as js only without too much react specific code.

Create a new file named assets/js/react-app.jsx and add the following:

// assets/js/react-app.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import TestComponent from './components/Test';


export default function renderApp(element) {
  ReactDom.render(<TestComponent />, element);
}

We’ll need to create an element on the page where we will render our react component to:

<!-- lib/yourapp_web/templates/page/index.html.heex -->

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

Finally, you can use the renderApp function in assets/js/app.js to render the app to an existing DOM element.

// assets/js/app.js

// ... other code generated by phoenix ...

import renderApp from './react-app'

// this assumes there is an element on the page with id=react-app
renderApp(document.getElementById('react-app'))

And now you should see the component rendered on the page.

Setting up Typescript

Now that we have React working, let’s get Typescript set up.

esbuild supports typescript out of the box, you just need to create a file with the .ts or .tsx extension and you’re done. Now, when I say “it supports typescript” I mean that it will happily compile your typescript to javascript but it will not do any type checking and error reporting, so you will need to set up the Typescript compiler to give you those checks.

Add the following to config/dev.exs to use the Typescript compiler (tsc) to do the type checking:

config :yourapp, YourappWeb.Endpoint,
  # .. other config ..
  watchers: [
    tsc: [
      "--jsx",
      "preserve",
      "--watch",
      "--noEmit",
      "--pretty",
    ],
    # .. other watchers
  ]

Let’s break this down:

  • --jsx preserve is telling the compiler to recognise JSX in your .tsx files.
  • --watch is pretty self explanatory.
  • --noEmit tells the compiler to only do type checking without transpiling anything (thus leaving that up to esbuild).
  • --pretty makes the output nicer with color highlights.

Now when you run mix phx.server, the typescript compiler will check your code for errors without doing any transpiling.

Fin.