Phoenix Live View is brand brand new so I thought I'd provide short write-up of a super simple demo I built for anyone looking to get up and running. Keep in mind that the library is still a release candidate and as such it it subject to change.
What is Live View?
Chris McCord said it best in his announcement back in December:
Phoenix Live View feels like a perfect fit for the 90% of the time that you do want some live updates but don't actually need the wrecking ball of many modern JS frameworks.
Let's get Live View up and running to support a feature that pushes out live updates as our server enacts a step-by-step process of creating a GitHub repo.
Here's the functionality we're building, notice how the "Status" updates in real-time:
The following steps are detailed in the Phoenix Live View Readme.
- Install the dependency in your
- Update your app's endpoint configuration with a signing salt for your live view connection to use. Note: you can generate a secret with
mix phx.secretfrom the command line.
- Update your configuration to enable writing Live View templates with the
- Add the live view flash plug to your browser pipeline, after
- Import the following in your
- Expose a socket for Live View to use in your endpoint module:
- Add Live View to your NPM dependencies:
- Your live views should be saved in the
lib/my_app_web/live/directory. For live page reload support, add the following pattern to your
Now we're ready to build and render a live view!
Rendering a Live View from the Controller
You can serve live views directly from your router. However, in this example we'll teach our controller to render a live view. Let's take a look at our controller:
We're calling on the
live_render/3 function which takes in an argument of the
conn, the live view we want to render, and any session info we want to send down into the live view.
Now we're ready to define our very own live view.
Defining the Live View
Our first live view will live in
my_app_web/live/github_deploy_view.ex. This view is responsible for handling an interaction whereby a user "deploys" some content to GitHub. This process involves creating a GitHub organization, creating the repo and pushing up some contents to that repo. We won't care about the implementation details of this process for the purpose of this example.
Our live view will use
Phoenix.LiveView and must implement two functions:
Now that we have the basic pieces in place, let's break down the live view process.
How It Works
The live view connection process looks something like this:
When our app receives an HTTP request for the index route, it will respond by rendering the static HTML defined in our live view's
render/1 function. It will do so by first invoking our view's
mount/2 function, only then rendering the HTML populated with whatever default values
mount/2 assigned to the socket.
The rendered HTML will include the signed session info. The session is signed using the signing salt we provided to our live view configuration in
config.exs. That signed session will be sent back to the server when the client opens the live view socket connection. If you inspect the page rendering your live view in the browser, you'll see that signed session:
Once that static HTML is rendered, the client will send the live socket connect request thanks to this snippet:
Now that we understand how the live view is first rendered and how the live view socket connection is established, let's render some live updates.
Rendering Live Updates
Live View is listening to updates to our socket and will re-render only the portions of the page that need updating. Taking a closer look at our
render/1 function, we see that it renders the values of the keys assigned to our socket.
mount/2 assigned the values
render/1 function renders them like this:
~L sigil represents Live EEx. This is the built-in Live View template. Unlike
.eex templates, LEEx templates are capable of tracking and rendering only necessary changes. So, if the value of
@deploy_step changes, our template will re-render only that portion of the page.
Let's give our user a way to kick off the "deploy to GitHub" process and see the page update as each deploy step is enacted.
Live View supports DOM element bindings to give us the ability to respond to client-side events. We'll create a "deploy to GitHub" button and we'll listen for the click of that button with the
phx-click event binding.
phx-click binding will send our click event to the server to be handled by
GithubDeployView. Events are handled in our live views by the
handle_event/3 function. This function will take in an argument of the event name, a value and the socket.
There are a number of ways to populate the
value argument, but we won't use that data point in this example.
Let's built out our
handle_event/3 function for the
Our function is responsible for two things. First, it will kick off the deploy process (coming soon). Then, it will update the value of the
:deploy_step key in our socket. This will cause our template to re-render the portion of the page with
<%= @deploy_step %>, so the user will see
Status: Ready! change to
Status: Starting deploy....
Next up, we need the "deploying to GitHub" process to be capable of updating the socket's
:deploy_step at each turn. We'll have our view's
handle_event/3 function send a message to itself to enact each successive step in the process.
This code is dummied-up--we're not worried about the implementation details of deploying our GitHub repo, but we can imagine how we might add error handling and other responsibilities into this code flow.
handle_event/3 function kicks off the deploy process by sending the
:create_org message to the view itself. Our view responds to this message by calling on code that enacts that step and by updating the socket. This will cause our template to re-render once again, so the user will see
Status: Starting deploy... change to
Status: Creating GitHub org.... In this way, the view enacts each step in the GitHub deploy process, updating the socket and causing the template to re-render each time.
Now that we have our live updates working, let's refactor the HTML code out of our
render/1 function and into its own template file.
Rendering a Template File
We'll define our template in
Next, we'll have our live view's
render/1 function simply tell our
PageView to render this template:
Now our code is a bit more organized.
From even this limited example, we can see what a powerful offering this is. We were able to implement this real-time feature with only server-side code, and not that many lines of server-side code at that! I really enjoyed playing around with Phoenix Live View and I'm excited to see what other devs build with it. Happy coding!