<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="380604" data-post-id="380604">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="rhcarvalho" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/rhcarvalho/120/32243_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  rhcarvalho
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="longnightElixir" data-post="1" data-topic="73715">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/longnightelixir/48/32051_2.png" class="avatar"> longnightElixir:</div>
<blockquote>
<p>For its in the same liveview, I have to add logics in <code> handle_params</code> to detect url changed then unsub, sub product_id related things.</p>
<p>are there some tools do this more elegantly ?</p>
</blockquote>
</aside>
<p>As far as I know, your intuition is right, implement conditional deregistration and registration as part of <code>handle_params/3</code> (possibly extracted into a <code>defp</code> helper.)</p>
<p>If you don’t already, store the current product ID in an assign. You can assign it to <code>nil</code> on <code>mount/3</code>, so that in <code>handle_params/3</code> you can easily distinguish if you just started and there’s no state to clean up, or if you navigated between products. Assign the current product ID in the <code>handle_params/3</code> callback.</p>
<p>Don’t forget to check the current product ID in your <code>handle_info/2</code> callback, and discard messages unrelated to the current product.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="380604" data-batch-url="/posts/batch_likers">
                        4
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/are-there-elegant-ways-to-sub-unsub-when-user-navigated-between-routers-in-same-liveview/73715/22">Post #21</a>
	                </div>
	            </div>
              <div id="likers-container-380604" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="380604"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #21"></div>
  </section>
</div>
    <div class="postbit" id="380619" data-post-id="380619">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="slouchpie" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/slouchpie/120/34819_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  slouchpie
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I have not read this thread completely but I did a search for the word “assign” and I don’t see anyone talking about modelling this.</p>
<p>I have done this sub/unsub thing before as a user patches between pages. It was not particularly elegant but it was simple.</p>
<p>For example, you might have an assign called <code>:product_topics</code> and maybe other assigns for other kinds of pubsub topics. In handle params, or wherever you assign the current product, unsubscribe from all topics in <code>:product_topics</code> and then create a new <code>product_topics</code> assign and subscribe to all those topics.</p>
<p>Do not listen to people telling you “should” or “should not” patch/navigate/redirect between pages. There is no absolute correct way here. It all depends on the reality of the situation, on the volume of the data.</p>
<p>TL;DR use assigns to “save” currently subscribed pubsub topics and work with these in <code>handle_params</code>.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="380619" data-batch-url="/posts/batch_likers">
                        3
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/are-there-elegant-ways-to-sub-unsub-when-user-navigated-between-routers-in-same-liveview/73715/23">Post #22</a>
	                </div>
	            </div>
              <div id="likers-container-380619" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="380619"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #22"></div>
  </section>
</div>
    <div class="postbit" id="380631" data-post-id="380631">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="garrison" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  garrison
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>What you and the above reply are suggesting is to <a href="https://legacy.reactjs.org/docs/reconciliation.html" rel="noopener nofollow ugc">write a reconciler</a> by hand. I gave a code example of this way up in reply 7, though I understand that it’s been kinda buried.</p>
<p>The problem, which I tried to explain at the time (but maybe not well enough?), is that this does not work in general in LiveView because there is no unmount.</p>
<p>As a simple example, say you have a live chat component that you want to embed into your LiveView. When the user opens it, it subscribes to the topic. LiveComponents cannot receive messages on their own but you can fix this with a router (see reply 3).</p>
<p>The problem is that when the surrounding LiveView decides to <em>close</em> the chat component, i.e. remove it from the page, it cannot unsubscribe from the resource because <em>there is no unmount callback</em> for it to use.</p>
<p>So the reconciler that all three of us have suggested here is incomplete. It is two thirds of a reconciler. It can <code>mount</code> and <code>update</code> but not <code>unmount</code>. This is not acceptable.</p>
<p>The reason you can get away with it in the simple case is luck: it just so happens that a root LiveView always replaces itself. This convenience <em>does not generalize to a real application</em>. Once you add more functionality to your app you will need components, and when that need comes the solution will break down.</p>
<p>One thing I’ve been wondering is how PhoenixSync handles this. I had a look at the code and <a href="https://github.com/electric-sql/phoenix_sync/blob/v0.6.1/lib/phoenix/sync/live_view.ex#L316" rel="noopener nofollow ugc">the router is there</a>, so you can indeed subscribe to a stream from a component. But where is the unsubscribe? I could be wrong, but I don’t see it. It kinda looks to me like the subscriptions are just held open forever when the components unmount.</p>
<p>LiveView needs a real solution to this problem. I will say again: if anyone actually <em>has</em> a solution, please post it. I do not.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="380631" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/are-there-elegant-ways-to-sub-unsub-when-user-navigated-between-routers-in-same-liveview/73715/24">Post #23</a>
	                </div>
	            </div>
              <div id="likers-container-380631" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="380631"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #23"></div>
  </section>
</div>
    <div class="postbit" id="380665" data-post-id="380665">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="cmo" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/cmo/120/19618_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  cmo
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="garrison" data-post="24" data-topic="73715">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/g/3bc359/48.png" class="avatar"> garrison:</div>
<blockquote>
<p>As a simple example, say you have a live chat component that you want to embed into your LiveView. When the user opens it, it subscribes to the topic. LiveComponents cannot receive messages on their own but you can fix this with a router (see reply 3).</p>
<p>The problem is that when the surrounding LiveView decides to <em>close</em> the chat component, i.e. remove it from the page, it cannot unsubscribe from the resource because <em>there is no unmount callback</em> for it to use.</p>
</blockquote>
</aside>
<p>It’s not as if there is no way to tell that the chat component was closed.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="380665" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/are-there-elegant-ways-to-sub-unsub-when-user-navigated-between-routers-in-same-liveview/73715/25">Post #24</a>
	                </div>
	            </div>
              <div id="likers-container-380665" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="380665"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #24"></div>
  </section>
</div>
    <div class="postbit" id="380677" data-post-id="380677">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="garrison" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  garrison
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>There is no way (that I know of!) to tell that the chat component was <em>unmounted</em>. Knowing that it was closed implies that you must keep track of all possible codepaths which will lead to the component being removed from the page. The advantage of declarative frameworks like React or LiveView is that you can write code without thinking about such things and therefore avoid bugs in complex codebases.</p>
<p>This is hard to teach/explain because it’s not a problem that shows up in trivial examples. It’s a problem that shows up in <em>real</em> apps, once the size of the codebase increases a couple orders of magnitude (as real codebases do).</p>
<p>To extend the example, say the chat box has a close button and you sprinkle some logic in there to unsubscribe from the topic. Then your app grows and you end up putting the chat box behind a tab bar that mounts/unmounts it.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">&lt;div class="tabs"&gt;
  &lt;div :if={@tab == "chat"}&gt;&lt;.live_component module={Components.Chat} /&gt;&lt;/div&gt;
  &lt;div :if={@tab == "something"}&gt;Something else&lt;/div&gt;
&lt;/div&gt;

defmodule TabComponent do
  def handle_event("set_tab", %{"tab" =&gt; tab}, socket) do
    {:noreply, assign(socket, :tab, tab)}
  end
end
</code></pre>
<p>How do you handle this? The tab bar has no concept of chat boxes. Do you add code to <code>set_tab</code> that runs the chat unsubscribe logic?</p>
<p>It’s much better for the <code>Chat</code> component to be able to declare, “if I am unmounted the topic comes with me”. That way, all of the code higher up in the tree does not need to <em>understand</em> what the <code>Chat</code> component does.</p>
<p>I hope that this makes sense, but if not then please let me know.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="380677" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/are-there-elegant-ways-to-sub-unsub-when-user-navigated-between-routers-in-same-liveview/73715/26">Post #25</a>
	                </div>
	            </div>
              <div id="likers-container-380677" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="380677"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #25"></div>
  </section>
</div>
    <div class="postbit" id="380689" data-post-id="380689">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="cmo" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/cmo/120/19618_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  cmo
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Well don’t put it there then.  I don’t think hidden behind a tab is where in the DOM I would put a chat widget that I presumably want to maintain state for the length of the user’s visit.</p>
<p>It makes sense.  I don’t think other people get so hung up on it though.  See the constraints and work within them.  It is more productive than seeing the constraints and doing little other than wishing they weren’t there. Considering how well versed you are in this topic, can’t you come up with a solution that works?</p>
<p>I think we all get your point that there is no unmount.  Armed with that knowledge, how can you design things that work within the constraints of the system?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="380689" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/are-there-elegant-ways-to-sub-unsub-when-user-navigated-between-routers-in-same-liveview/73715/27">Post #26</a>
	                </div>
	            </div>
              <div id="likers-container-380689" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="380689"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #26"></div>
  </section>
</div>
    <div class="postbit" id="380705" data-post-id="380705">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="garrison" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  garrison
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>The purpose of this example is to <em>communicate</em> the problem to you. I understand that there are situations where you would keep the component in the DOM, but there are <em>also</em> situations where you would not, and you can substitute those.</p>
<p>Sometimes things have workarounds, but I’m just not aware of a way to work around this particular issue. Honestly I was kinda hoping someone would pop by and say “actually, you fool, you can do XYZ”.</p>
<p>I provided a code example to reconcile subscriptions nearly a week ago, but I provided it with what I feel are the appropriate caveats. Namely, that it will leak the subscription when the component unmounts. I feel it would be negligent of me not to mention this.</p>
<p>You speak of constraints, but it’s hard not to notice that there are many <a href="https://legacy.reactjs.org/docs/hooks-effect.html#effects-with-cleanup" rel="noopener nofollow ugc">frameworks</a> for <a href="https://usegpu.live/docs/reference-live-@use-gpu-live--useResource" rel="noopener nofollow ugc">which</a> I <a href="https://preactjs.com/guide/v10/components#lifecycle-methods" rel="noopener nofollow ugc">could</a> <a href="https://docs.solidjs.com/reference/lifecycle/on-cleanup" rel="noopener nofollow ugc">provide</a> a <a href="https://vuejs.org/api/composition-api-lifecycle.html#onunmounted" rel="noopener nofollow ugc">working</a> <a href="https://svelte.dev/docs/svelte/lifecycle-hooks#onDestroy" rel="noopener nofollow ugc">implementation</a>.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="380705" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/are-there-elegant-ways-to-sub-unsub-when-user-navigated-between-routers-in-same-liveview/73715/28">Post #27</a>
	                </div>
	            </div>
              <div id="likers-container-380705" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="380705"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #27"></div>
  </section>
</div>
    <div class="postbit" id="380706" data-post-id="380706">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="garrison" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  garrison
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>As an aside, one idea I had was to use <code>phx-remove</code> (a client-side unmount event) to notify the component that it’s being unmounted, but this has obvious consistency issues. For one the component may already be gone, and for another it is actually very important in some cases that the old component be unmounted <em>before</em> the new one is mounted.</p>
<p>I believe any trickery with JS hooks would be similarly unworkable.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="380706" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/are-there-elegant-ways-to-sub-unsub-when-user-navigated-between-routers-in-same-liveview/73715/29">Post #28</a>
	                </div>
	            </div>
              <div id="likers-container-380706" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="380706"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #28"></div>
  </section>
</div>
    <div class="postbit" id="380729" data-post-id="380729">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="rhcarvalho" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/rhcarvalho/120/32243_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  rhcarvalho
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="garrison" data-post="28" data-topic="73715">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/g/3bc359/48.png" class="avatar"> garrison:</div>
<blockquote>
<p>there are many <a href="https://legacy.reactjs.org/docs/hooks-effect.html#effects-with-cleanup" rel="noopener nofollow ugc">frameworks</a> for <a href="https://usegpu.live/docs/reference-live-@use-gpu-live--useResource" rel="noopener nofollow ugc">which</a> I <a href="https://preactjs.com/guide/v10/components#lifecycle-methods" rel="noopener nofollow ugc">could</a> <a href="https://docs.solidjs.com/reference/lifecycle/on-cleanup" rel="noopener nofollow ugc">provide</a> a <a href="https://vuejs.org/api/composition-api-lifecycle.html#onunmounted" rel="noopener nofollow ugc">working</a> <a href="https://svelte.dev/docs/svelte/lifecycle-hooks#onDestroy" rel="noopener nofollow ugc">implementation</a>.</p>
</blockquote>
</aside>
<p>AFAIK all of these JS frameworks give you “unmount” lifecycle hooks on the client side, not on the server. They are all fundamentally different from LiveView’s operation model.</p>
<aside class="quote no-group" data-username="garrison" data-post="29" data-topic="73715">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/g/3bc359/48.png" class="avatar"> garrison:</div>
<blockquote>
<p>I believe any trickery with JS hooks would be similarly unworkable.</p>
</blockquote>
</aside>
<p>Yet DOM patching happens client side. You can’t know a component will be unmounted server side without application knowledge, e.g. by knowing a certain assign affects the presence of a certain part of the HTML template.</p>
<p>That’s because it’s on the client that the decision is made whether a node moved across the DOM tree, a node content got replaced and the container is reused (i.e. no <code>phx-remove</code> event), or a DOM node is actually removed.</p>
<p>On the client side LiveView provides at least two ways to hook into the lifecycle of arbitrary DOM nodes (that don’t need to match 1:1 to any server side idea of “component”), in particular related to unmount: <code>phx-remove</code> and client hooks <code>destroyed</code> callback.</p>
<p>Note that the server side idea of a component (be it a function component or LiveComponent) is detached from the lifecycle of client-side DOM nodes, and they are not mapped 1:1.</p>
<hr>
<p>The OP doesn’t mention using LiveComponent, so bringing  back to elegant ways of managing state on the server side lifecycle, what I’ve seen and done in cases like that is use explicit functions called from the appropriate LiveView callbacks:</p>
<aside class="quote quote-modified" data-post="22" data-topic="73715">
  <div class="title">
    <div class="quote-controls"></div>
    <img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/rhcarvalho/48/32243_2.png" class="avatar">
    <div class="quote-title__text-content">
      <a href="https://forum.elixirforum.com/t/are-there-elegant-ways-to-sub-unsub-when-user-navigated-between-routers-in-same-liveview/73715/22" rel="nofollow">Are there elegant ways to sub/unsub when user navigated between routers in same liveview?</a> <a class="badge-category__wrapper " href="/c/questions-help/questions/53" rel="nofollow"><span data-category-id="53" style="--category-badge-color: #C14BFB; --category-badge-text-color: #000000; --parent-category-badge-color: #C14BFB;" data-parent-category-id="171" data-drop-close="true" class="badge-category --style-square --has-parent" title="Elixir Questions / Help"><span class="badge-category__name">Questions</span></span></a>
    </div>
  </div>
  <blockquote>
    As far as I know, your intuition is right, implement conditional deregistration and registration as part of handle_params/3 (possibly extracted into a defp helper.) 
If you don’t already, store the current product ID in an assign. You can assign it to nil on mount/3, so that in handle_params/3 you can easily distinguish if you just started and there’s no state to clean up, or if you navigated between products. Assign the current product ID in the handle_params/3 callback. 
Don’t forget to check…
  </blockquote>
</aside>

<p>For route changes in the same LV it’s <code>handle_params</code>. We could also have code in <code>handle_event</code>, for instance when form changes (e.g. filters) affect the state of the LV. Imagine a filter on the client would affect the list of desired PubSub subscriptions. I’ve given an example of <code>handle_event</code> → <code>push_patch</code> → <code>handle_params</code> in another thread, which demonstrates how to react to arbitrary page events, update/store state in the URL and re-render keeping everything consistently in sync.</p>
<aside class="quote quote-modified" data-post="17" data-topic="69743">
  <div class="title">
    <div class="quote-controls"></div>
    <img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/rhcarvalho/48/32243_2.png" class="avatar">
    <div class="quote-title__text-content">
      <a href="https://forum.elixirforum.com/t/add-params-opt-to-js-patch-and-js-navigate-and-opt-to-merge-phx-value/69743/17" rel="nofollow">Add `:params` opt to JS.patch and JS.navigate, and opt to merge `phx-value-*`</a> <a class="badge-category__wrapper " href="/c/chat-discussions/proposals-ideas/164" rel="nofollow"><span data-category-id="164" style="--category-badge-color: #cca771; --category-badge-text-color: #FFFFFF; --parent-category-badge-color: #cca771;" data-parent-category-id="165" data-drop-close="true" class="badge-category --style-square --has-parent"><span class="badge-category__name">Proposals: Ideas</span></span></a>
    </div>
  </div>
  <blockquote>
    Oh yeah, go for it! I didn’t mean to stop the exploration. Life is all about learning <img width="20" height="20" src="https://forum.elixirforum.com/images/emoji/apple/purple_heart.png?v=15" title="purple_heart" alt="purple_heart" class="emoji"> 

<img width="20" height="20" src="https://forum.elixirforum.com/images/emoji/apple/+1.png?v=15" title="+1" alt="+1" class="emoji"> 
I have the same requirement for some LiveViews I implement, and I do the following today. Assuming you fully control the URL params on the server, here’s a stripped down version showing how to keep socket assigns and URL params in sync: 
defmodule MyAppWeb.ExampleLive do
  use MyAppWeb, :live_view

  @impl true
  def render(assigns) do
    ~H"""
    &lt;Layouts.app&gt;
      &lt;.form for={@form}…
  </blockquote>
</aside>

<p>(The same idea can be used to manage PubSub subscriptions in response to arbitrary events keeping state in the URL in sync)</p>
<p>-–</p>
<p>We’re beyond the scope of the OP <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="380729" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/are-there-elegant-ways-to-sub-unsub-when-user-navigated-between-routers-in-same-liveview/73715/30">Post #29</a>
	                </div>
	            </div>
              <div id="likers-container-380729" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="380729"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #29"></div>
  </section>
</div>
    <div class="postbit" id="380735" data-post-id="380735">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="garrison" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  garrison
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="rhcarvalho" data-post="30" data-topic="73715">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/rhcarvalho/48/32243_2.png" class="avatar"> rhcarvalho:</div>
<blockquote>
<p>AFAIK all of these JS frameworks give you “unmount” lifecycle hooks on the client side, not on the server. They are all fundamentally different from LiveView’s operation model.</p>
</blockquote>
</aside>
<p>LiveView happens to be running on the server, but its operational model (from the perspective of the <em>user</em>) is roughly the same as React et al. LiveView is <em>stateful</em> on the server, and components release their resources (mostly through GC) on the server. That is why the lifecycle events (<code>mount/1</code>, <code>update/2</code>) also happen on the server.</p>
<p>As a simple thought experiment, ignoring backwards compatibility would you make the same point in favor of <em>removing</em> <code>update/2</code> from <code>LiveComponent</code>?</p>
<aside class="quote no-group" data-username="rhcarvalho" data-post="30" data-topic="73715">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/rhcarvalho/48/32243_2.png" class="avatar"> rhcarvalho:</div>
<blockquote>
<p>That’s because it’s on the client that the decision is made whether a node moved across the DOM tree, a node content got replaced and the container is reused (i.e. no <code>phx-remove</code> event), or a DOM node is actually removed.</p>
</blockquote>
</aside>
<p>I was vaguely aware of this from reading the code, but I’ve never seen it explicitly mentioned anywhere so thank you for the explanation.</p>
<p>And you make a very important point. If the information from the client is delayed, we run into the same consistency issue where <code>unmount</code> is run for a component <em>after</em> its replacement is <code>mount</code>ed. The problems this can cause are subtle, but it could lead to e.g. the old component unsubscribing from the topic that the new component just subscribed to. It would be better not to have to worry about such things.</p>
<p>But do you not see any way around this? I think you know the code better than I do, but it seems to me like a simple <code>MapSet</code> of ids on the server would be enough to fix this. The server does actually <em>have</em> all of the information needed to know which components are live; it rendered them to begin with!</p>
<aside class="quote no-group" data-username="rhcarvalho" data-post="30" data-topic="73715">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/rhcarvalho/48/32243_2.png" class="avatar"> rhcarvalho:</div>
<blockquote>
<p>We’re beyond the scope of the OP</p>
</blockquote>
</aside>
<p>Components are obviously on-topic (everyone will have to use them at some point), but if we’re talking about implementation details then I agree. It seems like my point is now understood, so I’m satisfied with that. It was not really my intent to advocate for change.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="380735" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/are-there-elegant-ways-to-sub-unsub-when-user-navigated-between-routers-in-same-liveview/73715/31">Post #30</a>
	                </div>
	            </div>
              <div id="likers-container-380735" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="380735"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #30"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <a class="load-more-button" data-turbo-stream="true" href="/topics/73715/load_more?page=4">Load more posts (2 remaining)</a>
</div></template></turbo-stream>