Retrieving state of a LiveView component

Hello, I feel somewhat silly, but I can’t figure out if there is a way to ask the component to return it’s state.

Let’s say I have a page PageLive which contains liveview component

<%= live_component @socket, MyApp.SomeComponent, data: init_data, id: :some_component1%>

The SomeComponent module looks like

defmodule MyApp.SomeComponent do
  use Phoenix.LiveComponent
  
  def add_data(id, new_data) do
    send_update(__MODULE__, id: id, new_data: new_data)
  end

  def mount(socket) do
    {:ok, assign(socket, data: [])}
  end

  def update(%{new_data: new_data, id: id}, socket) do
    data = socket.assigns.data ++ new_data
      |> make_changes_to_data()

    {:ok, assign(socket, data: data)}
  end
end

Since the component needs to make some changes to the data, how can I retrieve the data in SomeComponent assigns from the PageLive module?

1 Like

You can’t access the Component assigns from the Parent module. What you probably want to do is switch the source of truth from the Component to the Parent. Basically the Component should not handle updating the data - the Parent should update the data, and then pass that updated data directly into the Component assigns. Example (using current live_component syntax)

<.live_component module={MyApp.SomeComponent} data={updated_data} id={:some_component1} %>

When you make the Component update the data, you are basically making a design choice, that the Parent will not need the updated data. This doesn’t seem like what you want.

I see, thank you.

The thing is that the component for me in question is a graph plotting datapoints so it clips the data if there is too much of it. It is a reusable component so it makes sense that it implements this logic.

However, I also have a separate time picking livecomponent where you can change the timespan which is shown. Again, another reusable component and it’s logic doesn’t necessary have to be a part of graph component.

When the graph component clips the data, the time component should become aware of it and display the dates accordingly.

Any tips on that?

If the parent LiveView is the source of truth (basically meaning it has all the most up-to-date data), then you can give that data out to as many LiveComponents as you want. The timespan, datapoints, etc - all of it should be held in the parent LV assigns, and then the time-picker component and graph component will receive the necessary assigns from the parent using the syntax I showed above. Basically the work of updating and managing state, should be kept in the parent and not pushed into the child components.

If you really want to try to workaround this, you can try using send(self(), {:from_child, socket.assigns.updated_data}) to send data from component to parent, but then you are getting into murky waters where you are trying to maintain two sources of truth. It’s best to keep just one (the parent), and then have the children just handle the rendering of the parent’s data.

1 Like

Yeah, you are probably right…I’ll do it that way.
Thank you! :slight_smile: