live_props v0.2.2 LiveProps View Source
LiveProps is a library for managing properties and state within Phoenix LiveViews and Phoenix LiveComponents.
Features
Declaratively define props and state, initialize default values, and compute derived values using the
LiveProps.Prop.prop/3
andLiveProps.Prop.state/3
macros.Supports required props
Supports automatic re-computation of computed props and state
Props automatically added to module documentation.
Example
Inside a LiveView or LiveComponent, you must use LiveProps.LiveView
or LiveProps.LiveComponent
,
respectively. LiveComponents can have state and props, while a LiveView can only have state,
so we'll look at an example LiveComponent to demonstrate both.
Here's a simple Button component that just has props:
defmodule ButtonComponent do
use Phoenix.LiveComponent
use LiveProps.LiveComponent
prop :class, :string, default: "button"
prop :text, :string, default: "Click me"
prop :on_click, :string, default: "click_button"
def render(assigns) do
~L"""
<button class="<%= @class %>"
phx-click="<%= @on_click %>">
<%= @text %>
</button>
"""
end
In this example we define three props that will be automatically assigned default values, so you don't have to define your own mount or update callbacks to do it yourself.
defmodule MyAppWeb.ThermostatComponent do
# If you generated an app with mix phx.new --live,
# the line below would be: use MyAppWeb, :live_component
use Phoenix.LiveComponent
use LiveProps.LiveComponent
prop :user_id, :integer, required: true
prop :temperature, :float, compute: :get_temperature
state :mode, :atom, default: :verbose
def render(assigns) do
~L"""
<%= case @mode do %>
<% :verbose -> %>
Current temperature: <%= @temperature %>
<% _ -> %>
<%= @temperature %>
<% end %>
<button phx-click="toggle-mode" phx-target="<%= @myself %>">Toggle mode</button>
"""
end
def get_temperature(assigns) do
Thermostat.get_user_reading(assigns.user_id)
end
def handle_event("toggle-mode", _, %{assigns: assigns} = socket) do
new_mode = if assigns.mode == :verbose, do: :compact, else: :verbose
{:noreply, set_state(socket, :mode, new_mode)}
end
end
Our component requires a :user_id
prop, which it uses to fetch the temperature.
Since it is required, an error will be raised if you forget to pass it in.
We also have the :temperature
prop, which is a computed prop. This will be re-calculated
automatically anytime the :user_id prop changes. It is calculated by get_temperature/1
which
takes the socket assigns as an argument and returns the value to be assigned. Calculations are run
in the order defined so we could add even more computed props which depend on the temperature assign.
Lastly, the component has a state called :mode
which controls the display. We've given
it a default value, which is assigned on mount behind the scenes. We could also add computed states
that depend on other states. In the "toggle_mode" handler we use LiveProps.States.set_state/3
to
update the :mode
. We could have just done a regular Phoenix.LiveView.assign/3
call but
using set_state/3
is useful when we want to trigger the re-calculation of other states
as well (in this case, there are none).
Notice what our component does not have: a Phoenix.LiveComponent.mount/1
, Phoenix.LiveComponent.update/2
or Phoenix.LiveComponent.preload/1
callback. LiveProps handles that for you, by injecting lightweight callbacks
behind the scenes.
You can still define your own callbacks if you need to, and everything should continue to work.
In a LiveComponent, any callbacks
you define will be run after the the LiveProps callbacks (i.e. defaults and computed values
will already be assigned to the socket). The LiveProps.LiveComponent
documentation
has additional information on component lifecycles.
This module is not intended to be used directly but rather by means of
LiveProps.LiveView
and LiveProps.LiveComponent
. Please see docs for those
modules for additional information.