💕 Love.Component 💕
Fall in love with LiveComponents all over again.
Love.Component provides functionality on top of Phoenix.LiveComponent to improve developer ergonomics through a few simple conventions.
- Explicit assign definitions in three different buckets:
- Props are passed in to the component and are never updated internally
- State is managed entirely by the component
- Computed values are derived entirely from other values
- Simple reactivity so that computed values and other side-effects are automatically invoked when component state changes
- Runtime checks to ensure that everything you define has been assigned, and nothing you haven't defined isn't
Example
defmodule MyAppWeb.UserProfileComponent
use Phoenix.LiveComponent
use Love.Component
import Love.Component
prop :id
prop :profile
prop :show_avatar?, default: false
state :expand_details?, initial: false
computed :age
def handle_click("toggle-details", _, socket) do
{:noreply, put_state(socket, expand_details?: not socket.assigns.expand_details)}
end
@react to: :profile
def compute_age(socket) do
age = trunc(Date.diff(Date.utc_today(), socket.assigns.profile.birthday) / 365)
put_computed(socket, age: age)
end
end
The :id and :profile assigns are required props. If they are not passed in, a helpful runtime error will occur.
The :show_avatar? assign is an optional prop.
The :expand_details? assign is state and has an initial value. It can be modified via put_state/2.
The :age assign is computed and is set by put_computed/2. If we forget to set it, a helpful runtime error will occur.
The compute_age/1 function is a reactive callback. It is automatically evaluated whenever any of the assigns listed in the @react to: ... attribute have changed. The function can react to prop changes, state changes, and even other reactive callbacks.
Gotchas
Call super when overriding mount/1 and update/2
Love.Component implements the LiveComponent mount/1 and update/2 callbacks. If your component needs to override either of these functions, super/{1,2}must be invoked so that Live.Component can continue to work its magic.
Installation
The package can be installed by adding love_ex to your list of dependencies in mix.exs:
def deps do
[
{:love_ex, "~> 0.1.0"}
]
end