Learnings from my very first Phoenix LiveView app
The release of Phoenix 1.5 with LiveView integration gave me the perfect excuse to finally build a LiveView App. I decided to build a simple Decision Matrix app named Ruminate.io. For a deeper dive into the app, check out this series of articles that recounts the entire product development journey.
I’ve been keeping an eye on Phoenix LiveView ever since it was announced by Chris McCord back in 2018. However, this is my first attempt in building an entire app with it and there are some interesting learnings, insights, mistakes and challenges along the way.
For those who aren’t familiar with LiveView, you can start with this article. This is NOT an introduction guide but rather a collection of learnings and insights from my experience with LiveView.
Use mount/3 to initialize your state
LiveView turns the usual request-response cycle we are used to with controllers into a stateful process. mount/3
is the place to setup your default values for parameters and initial states of your view.
Apply Action as plug in Controllers
If you use mix phx.gen.live
to generate your LiveView, you may have noticed the apply_action/3
functions. It’s similar as having a plug in your controller to execute some code depending on the current action.
Everything goes through the socket
In a LiveView, the state is held in the socket’s assigns, so you will need to assign any data you want to use in your templates to the socket. Use assign/3
for any change you want propagated to the templates.
The fetch resource function
Also in the generated example, you’ll noticed the fetch_resource
function which fetches the data required by the LiveView. This function is called whenever you want to refresh your data after certain actions. I prefer to modify it to accept the socket in order to gain access to assigns and to be easily chain-able.
Subscribe to PubSub for Live Updates
Leveraging the fetch resource function above and Phoenix PubSub, your views can have live updates by implementing a handle_info/2
callback and subscribing to a topic. Don’t forget to broadcast any updates to the same topic.
Where all the action is at
The bulk of your code will be at the handle_params/3
or handle_event/3
callbacks. The former is called when you load the view and the latter when the user perform an action or event on it.
Patch vs Redirect
At first, I was quite confused when I should be using push_patch/2
vs push_redirect/2
as they seem inter-changeable if you are using it on the same LiveView.
Later on, I learned to use patch if I want to update the URL of the current LiveView and use redirect if it’s a different LiveView. The same applies to live_patch/2
and live_redirect/2
used in the templates.
Assign URI for current path
My entire app including the navigation bar are LiveViews. To highlight the current active tab on the navbar, I had to check if tab’s link matches the current path. The only way I could do it was to assign the uri
from the handle_params/3
callbacks.
Set Page Title in LiveView
In a normal Phoenix web app, it’s quite common to set the page title in the corresponding Phoenix View. Here, you can do it all in LiveView by assigning the page title to the socket. It can be updated just like any data in assigns at any time.
Customizing root and live templates
Due to the introduction of LiveView, Phoenix now have a root.html.leex
template that’s shared (LiveViews & non LiveViews templates) and a new live.html.leex
template specifically for LiveViews.
You can set custom root layouts from your router. To customise the live layout, I had to my web app macro and implement a new LiveView type.
LiveComponents
Think of LiveComponents as a way to group and structure related logic in one place. They can either be stateless or stateful. Remember to set phx-target
correctly else the event from the component will be handled by the LiveView instead.
Live Modal
In the generated code, you will also see a live_modal/3
function. It’s a LiveComponent that wraps another LiveComponent which can be configured. Basically, it’s a modal that’s managed from the LiveView rather than on the client side.
I also find it helpful for the modal state to have it’s own route so it can be triggered directly when loading the page.
Passing data to LiveComponents
A mistake I keep making is that I assume passing the socket to the LiveComponent will grant it access to all the socket’s assigns. This is not the case and you have to pass them individually.
Integration test is fun again
After struggling for years with headless browsers, integration test with Phoenix LiveView is a welcome change. It’s so much easier to test all the interactions and state changes without writing any Javascript. I managed hit 98% code coverage with relative ease.
LiveDashboard is awesome
If you are using LiveView, I suggest installing LiveDashboard to have a real time view of your application metrics and performance. I also show the current deployed commit hash on the dashboard for me to track what’s deployed currently. Don’t forget to only allow admin to access the dashboard.
Build a LiveView App today
I hope this article is helpful for those of you who are also trying out LiveView. It’s definitely a very different experience than your usual MVC web application and you get all the cool live update features from the get-go. For those of you who haven’t tried it, today is the day.
Cover Photo by Jefferson Santos on Unsplash