real shared state - new users get initial value correctly.

This commit is contained in:
Peter Hart 2022-08-28 13:18:09 -04:00
parent 87e5e79c04
commit 59f97236cd
3 changed files with 66 additions and 11 deletions

View File

@ -8,6 +8,8 @@ defmodule LiveViewCounter.Application do
@impl true
def start(_type, _args) do
children = [
# Start the App State
LiveViewCounter.Count,
# Start the Telemetry supervisor
LiveViewCounterWeb.Telemetry,
# Start the PubSub system

View File

@ -0,0 +1,55 @@
defmodule LiveViewCounter.Count do
use GenServer
alias Phoenix.PubSub
@name :count_server
@start_value 0
# ------- External API (runs in client process) -------
def topic do
"count"
end
def start_link(_opts) do
GenServer.start_link(__MODULE__, @start_value, name: @name)
end
def incr() do
GenServer.call @name, :incr
end
def decr() do
GenServer.call @name, :decr
end
def current() do
GenServer.call @name, :current
end
def init(start_count) do
{:ok, start_count}
end
# ------- Implementation (Runs in GenServer process) -------
def handle_call(:current, _from, count) do
{:reply, count, count}
end
def handle_call(:incr, _from, count) do
make_change(count, +1)
end
def handle_call(:decr, _from, count) do
make_change(count, -1)
end
defp make_change(count, change) do
new_count = count + change
PubSub.broadcast(LiveViewCounter.PubSub, topic(), {:count, new_count})
{:reply, new_count, new_count}
end
end

View File

@ -1,27 +1,25 @@
defmodule LiveViewCounterWeb.Counter do
use Phoenix.LiveView
alias LiveViewCounter.Count
alias Phoenix.PubSub
@topic "live"
@topic Count.topic
def mount(_params, _session, socket) do
LiveViewCounterWeb.Endpoint.subscribe(@topic)
{:ok, assign(socket, :val, 0)}
PubSub.subscribe(LiveViewCounter.PubSub, @topic)
{:ok, assign(socket, val: Count.current()) }
end
def handle_event("inc", _, socket) do
new_state = update(socket, :val, &(&1 + 1))
LiveViewCounterWeb.Endpoint.broadcast_from(self(), @topic, "inc", new_state.assigns)
{:noreply, new_state}
{:noreply, assign(socket, :val, Count.incr())}
end
def handle_event("dec", _, socket) do
new_state = update(socket, :val, &(&1 - 1))
LiveViewCounterWeb.Endpoint.broadcast_from(self(), @topic, "dec", new_state.assigns)
{:noreply, new_state}
{:noreply, assign(socket, :val, Count.decr())}
end
def handle_info(msg, socket) do
{:noreply, assign(socket, val: msg.payload.val)}
def handle_info({:count, count}, socket) do
{:noreply, assign(socket, val: count)}
end
def render(assigns) do