Phoenix LiveView live_link

In the previous article focused on live_redirect, we’ve seen how in Phoenix LiveView we can change the URL without changing the location or refreshing the page. In this way we can keep the URL updated with the current page state, making easier for the user to bookmark or share it.

We are going to see how to refactor the code with live_link, making the code simpler and reducing the number of messages exchanged between our browser and LiveView.

Pictures example with live_redirect/2

Let’s consider the LiveView Pictures page example, and see how, in this case, is convenient to use live_link/2 instead of live-redirect/2.

In this example we have a list of thumbnails. When we click on a thumbnail, LiveView changes the URL and updates the page showing the full-size image.

defmodule DemoWeb.PicturesLive do
  ...
  def render(assigns) do
    ~L"""
    ...
    
    <%= for {id, pic} <- pictures do %>
    
    <div class="column" 
         phx-click="show" 
         phx-value="<%= id %>">
      <%= pic.author %>
      <img src="<%= picture_url(pic.img, :thumb) %>">
    </div>
    
    <% end %>

    ...
    """
  end
end

Each thumbnail element has phx-click="show" and phx-value="<%= id %>" attributes. In this way when we click a thumbnail the "show" event is sent to the server along with the picture id.

def handle_event("show", id, socket) do
  {:noreply, live_redirect(socket, to: Routes.live_path(socket, DemoWeb.PicturesLive, id))}
end

The LiveView process handles this event with handle_event("show", id, socket) function, sending a live_redirect message back to the browser.

Inspect LiveView messages

Let’s see better what happens, checking the messages exchanged between the browser and Phoenix.

I’m using the Chrome inspector, but with other browsers should be similar.

We open the inspector, we select the network tab and clicking WS we show only the WebSocket connections. Refreshing the page we now see the WebSocket connection used by Phoenix LiveView and clicking on it we can see the messages exchanged between the browser and LiveView.

LiveView WS messages – phx-click and live_redirect

Clicking on a thumbnail we see four messages

[...,"event",{"type": "click", "event": "show", "value":"XesILKdmkwM"}]

[...,"live_redirect",{"kind": "push", "to": "/pictures/XesILKdmkwM"}]
[...,"link",{"url":"/pictures/XesILKdmkwM"}]

[...,"phx_reply",{"response":{"diff": {...}}}]
  • After changing the URL, the browser sends a message back to the server with the new URL.
  • LiveView processes this message with handle_params/3, renders the new page and sends back a response with the differences to apply on the page.

This back and forth of messages is redundant – we can avoid the first two messages (click and live_redirect) with live_link.

live_link

By using live_link we don’t need to handle the click event ourself. We can then remove the two attributes, phx-click and phx-values, along with the handle_event("show", id, socket) function.

defmodule DemoWeb.PicturesLive do

  def render(assigns) do
    ... 
    <%= for {id, pic} <- pictures do %>
    
      <%= live_link to: Routes.live_path(@socket, DemoWeb.PicturesLive, id) do %>

        <div class="column">
          <%= pic.author %>
          <img src="<%= picture_url(pic.img, :thumb) %>">
        </div>

      <% end %>
    <% end %>	
    ...
  end
end

We wrap our thumbnail tag with live_link and use the same Routes.live_path/3 function as we did with live_redirect – since we are inside a LiveView template, we just need to use @socket instead of socket.

We see how in this way the code becomes simpler and using the browser inspector, we also see that for each click we now have just two messages.

[...,"link",{"url":"http://localhost:4000/pictures/XesILKdmkwM"}]

[...,"phx_reply",{"response":{"diff": {...}}}]

With live_link, the browser changes immediately the URL without sending any click event (like we did before). Once changed, the new URL is sent to the server which re-renders the page and sends back a message with the differences to apply.

When using live_link and when live_redirect?

So, when to use live_link and when live_redirect?

In the Pictures example, the user interacts with the frontend clicking the links. It’s clear that live_link is the right choice – it makes the code simpler and we get less exchanged messages.

In the animated URL example though, there is no user interaction (apart from starting/stopping the animation). Every 100 milliseconds the server tells the browser to change the URL, so in this live_redirect is the way to go.