I added several required attr macros to my LiveComponent that was generated with phx.gen.live. I tried removing these attributes from where I’m using that component, but I don’t see any compiler warnings in my console. Do these only alert for Phoenix.Component, and not LiveComponent? I see from the source that LiveComponent uses Component so I’d imagine they’d behave the same way.
Versions:
{:phoenix, "~> 1.7.0-rc.0", override: true},
{:phoenix_live_view, "~> 0.18.3"},
Component:
attr :title, :string, required: true, doc: "Page title"
attr :navigate, :string, required: true, doc: "Route to navigate to after successful save"
@impl true
def render(assigns) do
Function Use:
<.live_component
module={IdoWeb.TripLive.FormComponent}
id={@trip.id}
/>
1 Like
attr
and slot
are tools for function components, not live components. You can make your live component use one top level function component however.
2 Likes
Ah ok, that’s disappointing. I figured the attrs is just as useful for LiveComponent as Component. Should Phoenix prevent using the attrs
macro in LiveComponent if it’s not going to provide anything?
Thanks!
Technically render/1
is a function component, but the whole LiveComponent isn’t. You’re not doing <SomeMod.render />
, because that wouldn’t make it stateful. Also keep in mind that the assigns passed to the LiveComponent (either passed in or using send_update
) don’t directly map to assigns used with render/1
, so I’m not sure how this would be supposed to be validated in the first place.
Got it. Then is there a recommended way to validate inputs to a live component? The hard thing for me is refactors- I add an attribute to my LiveComponent, but forget to update an instance that uses it. Hopefully a test will catch my mistake.
Just pattern match the render function to make it fail sooner?
def render(%{title: _title, navigate: _navigate} = assigns) do
What about providing a wrapper function component that creates the live component?
@doc “Renders the thing as a LiveComponent”
attr …
slot …
def live(assigns) do
~H”””
<.live_component module={__MODULE__} … />
“””
end
def render(assigns) do
…
end
# use as
<.MyComponent.live whatever={…} />
No idea if this is a good pattern to use, but I think it gets what you want.
5 Likes
Oh interesting. I wonder if passing through the assigns breaks any sort of caching? Guessing this will be no different from how it typically behaves?
<.live_component module={__MODULE__} {@assigns}/>
Would the wrapper component absort the id
attr, and then the inner component would be trying to use the same id (or no id)?
I am reading Elixir in Action and came across a feature called Registered Module Attributes, like @doc
& @moduledoc
.
So I was thinking, perhaps later LiveView can have 2 more registered module attributes, @attr
& @slot
, which will give meta information about the module itself.
So both, function components and live components can have feature parity.
There’s no fundamental difference here vs. a local function component that renders the live component! The wrapper would just declare id as a required attribute and pass it along to the live component. Function components don’t “eat” id — there’s nothing special about id (or any attribute that doesn’t start with :
, like :if, :for
etc).
Not sure exactly what you mean by caching — as in, the LiveView diffing algorithm? Shouldn’t run into any issues here!
I was referring to the requirement for LiveComponent’s to have an id. I thought that the id might be used by Phoenix so it wouldn’t be a part of the assigns. I don’t think there’s any such thing for function components, so the id will just be passed through no problem like you suggest.