Mob.Event.Component behaviour (mob v0.5.3)

Copy Markdown View Source

Behaviour for stateful event-owning components.

See guides/event_model.md for the model. In short:

  • Stateless components are plain functions: (assigns) -> render_tree. They have no event horizon — events fired inside their subtree resolve to the nearest stateful ancestor.
  • Stateful components implement Mob.Event.Component. They own events fired in their subtree and may escalate semantic events to their parent.

This is the Mob equivalent of Phoenix.LiveComponent.

Status

This is the interface declaration. The runtime that hosts these components — registering them in render trees, routing events to them, managing their lifecycle — is implemented incrementally:

  1. Existing Mob.Component (a sibling concept for native_view widgets) remains the runtime for components that pair with custom native views.
  2. Mob.Event.Component (this module) is the event-routing abstraction: a stateful owner of events for a subtree of standard widgets.
  3. The two will likely merge once the new event model is plumbed end-to-end.

Until then, the Bridge module handles the legacy event shapes and the existing Mob.Component is the canonical stateful component.

Callbacks

defmodule MyApp.CheckoutForm do
  use Mob.Event.Component

  def mount(props, state), do: {:ok, Map.put(state, :email, "")}

  def render(state) do
    # return a render tree (uses Mob.UI helpers)
    %{type: :column, ...}
  end

  def handle_event(%Address{id: :email}, :change, value, state) do
    {:noreply, %{state | email: value}}
  end

  def handle_event(%Address{id: :submit}, :tap, _, state) do
    # Escalate to parent — this is the "semantic" event.
    send(state.parent_pid, {:form_submitted, state.email})
    {:noreply, state}
  end
end

Summary

Callbacks

handle_event(addr, event, payload, state)

@callback handle_event(
  addr :: Mob.Event.Address.t(),
  event :: atom(),
  payload :: term(),
  state :: map()
) :: {:noreply, map()}

handle_info(message, state)

(optional)
@callback handle_info(message :: term(), state :: map()) :: {:noreply, map()}

mount(props, state)

@callback mount(props :: map(), state :: map()) :: {:ok, map()} | {:error, term()}

render(state)

@callback render(state :: map()) :: map()

terminate(reason, state)

(optional)
@callback terminate(reason :: term(), state :: map()) :: term()

update(props, state)

(optional)
@callback update(props :: map(), state :: map()) :: {:ok, map()}