Introducing ReactPhoenix - Render React.js components in Phoenix views
Check out the package at https://github.com/geolessel/react-phoenix
While I love Elixir and Phoenix, my current daily, pay-the-bills language at Planning Center is Ruby and Rails. We create a lot of React.js components as well and I really like working with React. So it is an obvious transition for me to want to use React components in my Phoenix applications as well.
Every time I started a new Phoenix application, it took me quite a while to remember how to get everything set up in Phoenix in order to display a React component. Beyond that, most of the tutorials I found that dealt with React and Brunch (vs Webpack) only rendered a single component. I’m more interested in React sprinkles in my app and the global rendering on every page load wasn’t working for me. I saw a hole in the current offerings of packages dealing with Phoenix and React and I decided to fill it.
ReactPhoenix
I created a package named react_phoenix to make it so much easier to get React components into your Phoenix views. It is heavily inspired by the react-rails gem that I use every day. I wanted something with as little installation pains as possible and that got out of my way when all I wanted to do was render a component in a view. Here’s how it works.
Prerequisites
To begin with, your Phoenix app should already have React installed as a dependency. Beyond that, I recommend that you have a couple of Babel presets installed and active as well in order for brunch to know how to compile those javascript component files.
> npm install react babel-preset-react babel-preset-env --save
Activate the presets in babel
by adding this to your brunch-config.js
file.
exports.config = {
// ...
plugins: {
babel: {
presets: ["env", "react"],
ignore: [/web\/static\/vendor/]
}
},
// ...
}
Installation
I tried to make the README for the package detailed as I could in this part, but I’ll mirror it here. I should state that as of this writing (and the official public unveiling), the package is at version 0.3.0, which is what these steps pertain to. It is unlikely this part will change much in the future, but just in case, you may want to check that README if things don’t seem to be working. Also, we will be using Phoenix 1.2. I haven’t tested this in Phoenix 1.3 quite yet.
Step 1
Add ReactPhoenix as a dependency in your mix.exs
file.
def deps do
[
{:react_phoenix, "~> 0.3.0"}
]
end
then run mix deps.get
.
Step 2
Add the included javascript helper to our package.json
file (in the
dependencies section).
{
"dependencies": {
"phoenix": "file:deps/phoenix",
"phoenix_html": "file:deps/phoenix_html",
"react-phoenix": "file:deps/react_phoenix" <-- ADD THIS!
}
}
then run npm install
.
Step 3
Import the javascript file into our web/static/js/app.js
bundle.
import "react-phoenix"
Step 4 (optional)
Sometimes it’s nice to be able to call just the function name and not the full
name of the function that includes the module name. In order to do so, edit your
web/web.ex
file and add an import
for ReactPhoenix.
def view do
quote do
use Phoenix.View, root: "web/templates"
import Phoenix.Controller, only: [get_csrf_token: 0, get_flash: 2, view_module: 1]
use Phoenix.HTML
import MyPhoenixApp.Router.Helpers
import MyPhoenixApp.ErrorHelpers
import MyPhoenixApp.Gettext
import ReactPhoenix # <-- ADD THIS!
end
end
Let’s render some React!
Now that we have everything set up, let’s render some React
components. Create a simple component we can use to make sure things
are hooked up correctly. In web/static/js/components/hello.jsx
:
Create a component
import React from "react"
export default class Hello extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
<h1>Hello {this.props.name}</h1>
)
}
}
import
the component
Let our javascript environment know that this component exists
and we’d like to make it available in web/static/js/app.js
.
import Hello from "./components/hello"
window.Components = {
Hello
}
Render the component
Use ReactPhoenix to render this component in a Phoenix view:
<%= react_component("Components.Hello", %{name: "React"}) %>
# or, if you haven't added import ReactPhoenix in web/web.ex
<%= ReactPhoenix.react_component("Components.Hello", %{name: "React"}) %>
Here we are telling ReactPhoenix that we’d like to render a component registered
as Components.Hello
(which we did in app.js
) and pass it props of name: "React"
.
View the results
And that’s it! You should be able to reload your view and see your React component lovingly rendered with the specified props.
A little video version
I took a quick video of me setting up a new Phoenix app and getting
React in it with ReactPhoenix. I go from mix phoenix.new
to getting
a React component rendered in a view in 4 minutes (including
typos!).
The future
I’d love to keep expanding this and making it better. I’ve already got it
working in a Phoenix app that does server-side React component rendering (using
a couple of other packages and the target_id
option in
ReactPhoenix.react_component/3
) but there are ways I can make this even
better. PLEASE reach out to me with any issues or suggestions you have to
make it better, easier, more robust, faster, whatever. I’d love to hear them.
You can check out the hex docs at https://hexdocs.pm/react_phoenix/readme.html and see the code on GitHub at https://github.com/geolessel/react-phoenix.
Get in touch with me on twitter at @geolessel and @geo in the Elixir slack group. I also have a newsletter that I’d be grateful if you signed up for below. I have some fun ideas brewing that I’d love to keep you informed about in the future. Thanks!
Buy my book—Phoenix in Action
I've been working hard on the first book on the Phoenix framework from Manning Publications, Phoenix in Action. If you like what you've been reading and/or you have an interest in learning Phoenix, please purchase the book today! Want to know more, check out my blog post announcing the book or the one announcing its completion.