live_store v0.1.0 LiveStore View Source
Share reactive state across nested LiveView's
Example
Root LiveView
defmodule MyAppWeb.CounterLive do
use Phoenix.LiveView
def render(assigns) do
~L"""
<h1><%= @val %></h1>
<%# render child template and pass the store pid with session %>
<%= live_render @socket, UsersFlaskWeb.CounterButtonLive, session: %{store: @store} %>
"""
end
def mount(_session, socket) do
# create a store in root component and subscribe for `:val` changes
store =
LiveStore.create(val: 0)
|> LiveStore.subscribe([:val])
socket =
socket
# store the pid of the store to assigns
|> assign(store: store)
# copy store `:val` to LiveView assigns
|> assign(LiveStore.take(store, [:val]))
{:ok, socket}
end
# handle all store changes by copying them to assigns
def handle_info({:store_change, key, val}, socket) do
{:noreply, assign(socket, key, val)}
end
end
Child LiveView
defmodule MyAppWeb.CounterButtonLive do
use Phoenix.LiveView
def render(assigns) do
~L"""
<button phx-click="inc"><%= @val %></button>
"""
end
# retrieve the store pid from the session
def mount(%{store: store}, socket) do
if connected?(socket) do
# subscribe for `:val` changes
LiveStore.subscribe(store, [:val])
end
socket =
socket
# store the pid of the store to assigns
|> assign(store: store)
# copy store `:val` to LiveView assigns
|> assign(LiveStore.take(store, [:val]))
{:ok, socket}
end
# handle all store changes by copying them to assigns
def handle_info({:store_change, key, val}, socket) do
{:noreply, assign(socket, key, val)}
end
# update store instead of the assigns
def handle_event("inc", _, socket = %{assigns: %{store: store}}) do
LiveStore.update(store, :val, &(&1 + 1))
{:noreply, socket}
end
end
Link to this section Summary
Functions
Adds key value pairs to store assigns. A single key value pair may be passed, or a keyword list of assigns may be provided to be merged into existing store assigns.
Returns a specification to start this module under a supervisor.
Creates a store with initial assigns. Returns store pid.
Gets the value for a specific key in store assigns.
Invoked when the server is started. start_link/3 or start/3 will
block until it returns.
Subscribes for assign changes.
Returns a map with all the key-value pairs in map where the key is in keys.
Updates an existing key in the store assigns. The update function receives the current key's value and returns the updated value. Raises if the key does not exist.
Link to this section Functions
Adds key value pairs to store assigns. A single key value pair may be passed, or a keyword list of assigns may be provided to be merged into existing store assigns.
Examples
iex> assign(store, :name, "Elixir")
iex> assign(store, name: "Elixir", logo: "💧")
Returns a specification to start this module under a supervisor.
See Supervisor.
Creates a store with initial assigns. Returns store pid.
Examples
iex> create(name: "Elixir")
iex> create(name: "Elixir", logo: "💧")
Gets the value for a specific key in store assigns.
If key is present in assigns, then value is returned.
Otherwise, default is returned.
Examples
iex> get(store, :name)
iex> get(store, :name, "Elixir")
Invoked when the server is started. start_link/3 or start/3 will
block until it returns.
init_arg is the argument term (second argument) passed to start_link/3.
Returning {:ok, state} will cause start_link/3 to return
{:ok, pid} and the process to enter its loop.
Returning {:ok, state, timeout} is similar to {:ok, state},
except that it also sets a timeout. See the "Timeouts" section
in the module documentation for more information.
Returning {:ok, state, :hibernate} is similar to {:ok, state}
except the process is hibernated before entering the loop. See
c:handle_call/3 for more information on hibernation.
Returning {:ok, state, {:continue, continue}} is similar to
{:ok, state} except that immediately after entering the loop
the c:handle_continue/2 callback will be invoked with the value
continue as first argument.
Returning :ignore will cause start_link/3 to return :ignore and
the process will exit normally without entering the loop or calling
c:terminate/2. If used when part of a supervision tree the parent
supervisor will not fail to start nor immediately try to restart the
GenServer. The remainder of the supervision tree will be started
and so the GenServer should not be required by other processes.
It can be started later with Supervisor.restart_child/2 as the child
specification is saved in the parent supervisor. The main use cases for
this are:
- The
GenServeris disabled by configuration but might be enabled later. - An error occurred and it will be handled by a different mechanism than the
Supervisor. Likely this approach involves callingSupervisor.restart_child/2after a delay to attempt a restart.
Returning {:stop, reason} will cause start_link/3 to return
{:error, reason} and the process to exit with reason reason without
entering the loop or calling c:terminate/2.
Callback implementation for GenServer.init/1.
Subscribes for assign changes.
Examples
# in mount
subscribe(store, [:count, :sum])
# handle change events and put them directly to assigns
def handle_info({:store_change, key, val}, socket) do
{:noreply, assign(socket, key, val)}
end
Returns a map with all the key-value pairs in map where the key is in keys.
If keys contains keys that are not in map, they're simply ignored.
Examples
iex> take(store, [:name, :logo])
Updates an existing key in the store assigns. The update function receives the current key's value and returns the updated value. Raises if the key does not exist.
Examples
iex> update(store, :count, fn count -> count + 1 end)
iex> update(store, :count, &(&1 + 1))