Lavash.LiveView.Explicit (Lavash v0.4.0-rc.3)

Copy Markdown View Source

Non-DSL entry point for using the Lavash reactive graph from a plain Phoenix.LiveView.

This is the path for "I want the reactive recomputation machinery without the Spark DSL, the ~L template transformer, or the optimistic JS hook." You get the dependency graph and automatic recomputation; you write mount/3, handle_event/3, and render/1 like any other Phoenix.LiveView.

Compare with use Lavash.LiveView, which adds the DSL (state, actions), the template transformer (~L), URL/socket-backed state, forms, bindings, overlays, and the optimistic JS hook — a much larger API surface in exchange for less code at the call site.

Example

defmodule MyAppWeb.CounterLive do
  use Lavash.LiveView.Explicit

  reactive do
    state :count, 0
    state :step, 1
    derive :doubled, rx(@count * @step)
  end

  @impl Phoenix.LiveView
  def handle_event("inc", _, socket) do
    {:noreply, put_state(socket, :count, &(&1 + 1))}
  end

  @impl Phoenix.LiveView
  def render(assigns) do
    ~H"""
    <p>{@count} (doubled = {@doubled})</p>
    <button phx-click="inc">+</button>
    """
  end
end

What use Lavash.LiveView.Explicit does for you

  • use Phoenix.LiveView and imports Lavash.Rx.rx/1.
  • mount/3 is provided automatically and calls Lavash.Reactive.init/2 with the graph built from reactive do ... end. You can override it; super(params, session, socket) does the lavash init.
  • handle_info/2 dispatches {:lavash_reactive, ...} messages from async derives to Lavash.Reactive.handle_async/2. Other messages fall through to the user's clauses.
  • put_state/3 is a single-call helper that combines Lavash.Reactive.put/3 + Lavash.Reactive.recompute/1 so you can't forget the recompute.
  • The graph is cached in :persistent_term. An @after_compile hook drops the cache when the module recompiles in dev.

What's NOT included

  • No URL-backed or socket-backed state; you wire handle_params/3 yourself.
  • No ~L template transformer. Use ~H. No auto-injected data-lavash-* attributes.
  • No optimistic JS hook. Updates take a server round-trip.
  • No bind=, no <.lavash_component>, no forms, no overlays. These are DSL features.

Summary

Functions

Mutates a state field and immediately recomputes the dependent graph.

Declares the reactive graph for this LiveView.

Functions

put_state(socket, field, value_or_fun)

Mutates a state field and immediately recomputes the dependent graph.

Equivalent to Lavash.Reactive.put/3 |> Lavash.Reactive.recompute/1 but in one call so the "forgot to recompute" footgun goes away.

def handle_event("inc", _, socket) do
  {:noreply, put_state(socket, :count, &(&1 + 1))}
end

Accepts either a literal value or a 1-arity function that receives the current value.

reactive(list)

(macro)

Declares the reactive graph for this LiveView.

Accepts a block of state name, default and derive name, rx_expr (with optional opts) calls. Translates to a Lavash.Reactive builder pipeline at compile time.

reactive do
  state :count, 0
  derive :doubled, rx(@count * 2)
  derive :slow, rx(fetch(@count)), async: true
end