Hello,
I’ve created a stream in a parent liveview that I want passed to a live_component. On the parent, when I create the stream:
socket
|> stream(:my_stream, [])
|> tap(fn x -> IO.inspect(x.assigns) end)
The stream is placed under the streams key in the sockets assigns as indicated:
streams: %{
__changed__: MapSet.new([:medications]),
my_stream: %Phoenix.LiveView.LiveStream{
name: :medications,
dom_id: #Function<3.112696910/1 in Phoenix.LiveView.LiveStream.new/4>,
ref: "0",
inserts: [],
deletes: [],
reset?: false,
consumable?: false
},
__configured__: %{},
__ref__: 1
},
However, the minute I attempt the assign that stream to the list of assigns for a component or a live component:
Component:
<.form_step
form={@current_form}
...
my_stream={@streams.my_stream}
...
/>
Live Component:
<.live_component
module={Web.Live.Common.StreamTest}
id="med-search-id"
my_stream={@my_stream}
/>
The stream is now in the assigns as:
my_stream: %Phoenix.LiveView.LiveStream{
name: :my_stream,
dom_id: #Function<3.112696910/1 in Phoenix.LiveView.LiveStream.new/4>,
ref: "0",
inserts: [],
deletes: [],
reset?: false,
consumable?: false
},
This all makes sense to me. After all I’m literally assigning the stream into the assigns.
This issue comes into play when I attempt to call stream_insert/4. The stream is no longer in socket.assigns.stream, it’s in socket.assigns. So the call to stream_insert fails:
** (KeyError) key :streams not found in: %{
id: "med-search-id",
__changed__: %{med_search_list: true, med_search_loading: true},
flash: %{},
myself: %Phoenix.LiveComponent.CID{cid: 1},
my_stream: %Phoenix.LiveView.LiveStream{
name: :my_stream,
dom_id: #Function<3.112696910/1 in Phoenix.LiveView.LiveStream.new/4>,
ref: "0",
inserts: [],
deletes: [],
reset?: false,
consumable?: false
},
My situation revolves around a live component so my work around is to just assign a regular list in the live_view, and in the live_component declare a stream. BUT since I’m maintaining the sources-of-truth’s in the live_view, I have to update both the stream AND regular list. The regular list being the source of truth for which I can do things to, and the stream for displaying the source of truth (because I can’t access the stream in the parent live view.)
new_state =
state
|> Map.put(:id, Ecto.UUID.generate())
socket
|> stream_insert(:my_stream, new_state)
|> update(:my_list_for_stream_in_live_component, fn states ->
[new_state | states]
end)
Seems hacky and probably unnecessary. This this not the intended purpose of streams? Am I missing something trying to get a stream into a component/live component? Should I just keep to the temporary_assigns and phx-update=“append” method for things like this?