Surface UI Stateless component rerender only on props change

Let’s say I have such component:

defmodule Hello do
  use Surface.Component

 prop(user_id, :integer, required: true)

  def render(assigns) do
    Hello #{find_user(@user_id).name}!

As it is now, the component will execute the render function every time parent component renders.

I can cache find_user/1 myself, but I was wondering if there is a pattern in LiveView or Surface UI that I am missing, which would result in component only fully rerendering when it’s props change?

Note: I am aware I can turn it into stateful component but that’s requiring adding ids and explicitly handling the state, something ideally I’d like to avoid.

Pass the user as the property. As it is, liveview can not be sure that find_user/1 is a pure function vso it had to be rerun every time.

1 Like

Well yes, it’s a synthetic example and in reality, things are a bit more convoluted.

I know React.memo() is doing precisely what I want in React environment.

In my actual use case, I am working with Surface components with slots, that work as a provider for their child components.

I ended up not memorizing render/1 function calls at all, but instead, I am caching the function calls that talk to the database to fetch the data. This removes the bottleneck I was experiencing, which was refetching the data from DB on each render. The solution I came up with uses Nebulex and caches a single instance of module/function call with latest list of arguments per process. When arguments change or the process dies, cache is invalidated.

Seems to work alright for now in the app, I’ll keep you posted if I come up with something smarter.

A good rule of thumb is to never access the database from view funtions, which are anything directly or indirectly called from the templates. Gather all the data from the handle_* functions and stuff them in socket assigns for the templates.


Right, so creating stateful components instead.

You don’t have to create stateful components if you put all the states in the parent liveview.