DEV Community

Cover image for Optimize LiveView Performance with Temporary Assigns
Rushikesh Pandit
Rushikesh Pandit

Posted on

Optimize LiveView Performance with Temporary Assigns

When working with Phoenix LiveView, you often juggle a lot of data while building interactive, real-time web applications. One challenge developers face is managing memory efficiently, especially for components or pages that render frequently changing data. Temporary assigns in LiveView provide a smart way to handle this challenge.

In this blog, we’ll dive deep into what temporary assigns are, why you should use them, and provide practical examples to help you harness their power effectively.

What Are Temporary Assigns?

Temporary assigns are a feature of Phoenix LiveView that lets you specify certain assigns to be reset to their default value after every render. This means LiveView doesn’t persist these values in memory, which can save significant resources when dealing with large or frequently changing data.

Without temporary assigns, all the assigns in your LiveView process are kept in memory between renders. While this is fine for small, static data, it can quickly add up when you’re working with dynamic content, such as lists, logs, or real-time updates.

Why Use Temporary Assigns?

Here are a few scenarios where temporary assigns can be particularly helpful:

  1. Reducing Memory Usage: If you have a LiveView that frequently updates large datasets (e.g., a chat app or a live dashboard), temporary assigns prevent stale data from piling up in memory.
  2. Improving Performance: By resetting unused data after each render, you reduce the load on your LiveView processes, keeping them lightweight and efficient.
  3. Preventing Memory Leaks: Long-running LiveView processes with large, unused assigns can inadvertently cause memory leaks. Temporary assigns are a built-in safeguard against this.

Setting Up Temporary Assigns

To enable temporary assigns, use the temporary_assigns key in the socket's assign function. Here’s a basic example:

def mount(_params, _session, socket) do
  {:ok, 
   assign(socket, 
     messages: [], 
     temporary_assigns: [messages: []]
   )}
end

Enter fullscreen mode Exit fullscreen mode

In this example, we’ve marked the messages assign as temporary. After every render, messages will reset to an empty list ([]), regardless of its previous state.

A Practical Example: Live Chat with Temporary Assigns

Let’s build a live chat application where messages are sent in real time. Without temporary assigns, the LiveView process would hold onto every single message, leading to bloated memory usage over time. Instead, we’ll use temporary assigns to keep the memory footprint minimal.

LiveView Module

defmodule MyAppWeb.ChatLive do
  use Phoenix.LiveView

  def mount(_params, _session, socket) do
    {:ok, 
     assign(socket, 
       messages: [], 
       temporary_assigns: [messages: []]
     )}
  end

  def handle_event("send_message", %{"content" => content}, socket) do
    message = %{content: content, timestamp: DateTime.utc_now()}

    # Append the new message to the messages list
    {:noreply, assign(socket, messages: [message])}
  end
end
Enter fullscreen mode Exit fullscreen mode

LiveView Template

<div id="chat-container">
  <div id="messages">
    <%= for message <- @messages do %>
      <div class="message">
        <p><%= message.content %></p>
        <small><%= message.timestamp %></small>
      </div>
    <% end %>
  </div>

  <form phx-submit="send_message">
    <input type="text" name="content" placeholder="Type a message..." required />
    <button type="submit">Send</button>
  </form>
</div>

Enter fullscreen mode Exit fullscreen mode

In this example:

  • @messages is marked as a temporary assign, so it resets to [] after each render.
  • The messages list is only populated during the render lifecycle, reducing the memory overhead.

Testing Temporary Assigns in Action

To see the difference temporary assigns make, you can log the state of the socket after each event:

def handle_event("send_message", %{"content" => content}, socket) do
  message = %{content: content, timestamp: DateTime.utc_now()}
  updated_socket = assign(socket, messages: [message])

  IO.inspect(updated_socket.assigns, label: "Socket Assigns After Render")

  {:noreply, updated_socket}
end

Enter fullscreen mode Exit fullscreen mode

Run the application and observe how @messages is reset to its default state ([]) after each render.

When Not to Use Temporary Assigns

While temporary assigns are incredibly powerful, they aren’t always the right tool. Avoid using them if:

  1. You need persistent data: For example, user session data or application state that shouldn’t be lost between renders.
  2. The cost of re-fetching data is too high: If the data comes from an external API or a complex computation, temporary assigns might introduce unnecessary overhead.

Advanced Use Cases

Combining Temporary Assigns with Streams

For large datasets that change incrementally (e.g., logs or paginated results), combine temporary assigns with LiveView streams for optimal performance.

def mount(_params, _session, socket) do
  {:ok, 
   socket
   |> assign(:logs, [])
   |> stream(:logs, [])
   |> assign(temporary_assigns: [logs: []])
  }
end

Enter fullscreen mode Exit fullscreen mode

This approach ensures that only the current batch of logs is in memory, while older logs are efficiently managed using streams.

Final Thoughts

Temporary assigns in Phoenix LiveView are an elegant solution to a common problem in real-time web development: managing memory while maintaining interactivity. By understanding when and how to use them, you can build scalable, performant applications without sacrificing user experience.

If you’ve used temporary assigns in your projects or have tips to share, let me know in the comments—I’d love to hear how you’re optimizing your LiveView apps!

Feel free to reach out if you need help.

LinkedIn: https://www.linkedin.com/in/rushikesh-pandit
GitHub: https://github.com/rushikeshpandit
Portfolio: https://www.rushikeshpandit.in

#myelixirstatus , #elixir , #phoenixframework

Top comments (0)