From 59f97236cdc4e7616f89f2edab2bcf34020978a8 Mon Sep 17 00:00:00 2001 From: Peter Hart Date: Sun, 28 Aug 2022 13:18:09 -0400 Subject: [PATCH] real shared state - new users get initial value correctly. --- lib/live_view_counter/application.ex | 2 + lib/live_view_counter/counter.ex | 55 +++++++++++++++++++++++ lib/live_view_counter_web/live/counter.ex | 20 ++++----- 3 files changed, 66 insertions(+), 11 deletions(-) create mode 100644 lib/live_view_counter/counter.ex diff --git a/lib/live_view_counter/application.ex b/lib/live_view_counter/application.ex index 5240e3e..ac5a43a 100644 --- a/lib/live_view_counter/application.ex +++ b/lib/live_view_counter/application.ex @@ -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 diff --git a/lib/live_view_counter/counter.ex b/lib/live_view_counter/counter.ex new file mode 100644 index 0000000..82da980 --- /dev/null +++ b/lib/live_view_counter/counter.ex @@ -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 diff --git a/lib/live_view_counter_web/live/counter.ex b/lib/live_view_counter_web/live/counter.ex index 6fe8d3f..a3926ce 100644 --- a/lib/live_view_counter_web/live/counter.ex +++ b/lib/live_view_counter_web/live/counter.ex @@ -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