Don't want to miss out on Elixir news? Subscribe to ElixirPulse!

What if mount had separate function heads for (dis)connected render?

If you’ve spent any time reading or writing LiveView, you have undoubtedly seen code that looks a lot like this:

def mount(params, session, socket) do
  if connected?(socket) do
    # connected mount
  else
    # disconnected mount
  end
end

Right away the mount/3 callback is checking to see if the socket is connected. Generally it’s so that the “heavy lifting” of loading items from the database or making network calls is only done once the websocket connection is established. This makes sense because it would be wasteful to make all of those calls just to throw away the results and do it all over again once the websocket connection is established.

But something never sat quite right about the way it was implemented. After all, Elixir heavily promotes pattern matching and it’s one of the things I love most about the language.

For a while I assumed that connected?/1 was implemented as a function and not a guard because it needed to do some sort of analysis at runtime to determine whether or not there was an active websocket connection.

One day I decided to finally peek under the covers and see for myself:

# phoenix_live_view.ex

def connected?(%Socket{transport_pid: transport_pid}), do: transport_pid != nil

Nope. The implementation of connected?/1 is a one line nil check.

Now we must ask the question: Can we make this a guard?

Turns out, we can! And it’s pretty simple, too:

defguard is_connected?(socket) when socket.transport_pid != nil

We can make this guard available to all of our liveviews by simply dropping the line inside of our live_view definition inside app_web.ex:

def live_view do
  quote do
    use Phoenix.LiveView,
      layout: {JohnElmLabsWeb.Layouts, :app}

    unquote(html_helpers())
    # Add the line here:
    defguard is_connected?(socket) when socket.transport_pid != nil
  end
end

Now we can break apart our disconnected and connected mounts with ease:

def mount(params, session, socket) when is_connected?(socket) do
  # Connected mount
end

def mount(params, session, socket) do
  # Disconnected mount
end

And that’s all it takes. Will you use this in your LiveViews going forward? I know I sure will.