README.md

# LiveStore

Share reactive state across nested [LiveView](https://github.com/phoenixframework/phoenix_live_view)'s

## Installation

The package can be installed by adding `live_store` to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:live_store, "~> 0.1.0"}
  ]
end
```

## Usage

Root LiveView

```elixir
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

```elixir
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
```

<img src="priv/img/example.gif" width="200" height="300"/>