longnightElixir
Hi, I have some usage scenario to ask:
Users navigate between ` /product/product_a_id ` and ` /product/product_b_id` , and more ;
these routers are in the same liveview;
I have background running jobs will send events (and data) to users who is staying on specified product detail page; this may approach by using Pubsub or Register;
The user who left ` /product/product_a_id ` should not receive those event sent to product_a, but he should receive event sent to product_b for he navigated there.
For its in the same liveview, I have to add logics in handle_params to detect url changed then unsub, sub product_id related things.
are there some tools do this more elegantly ?
Thanks !
Trending in Questions
Hello!
Suppose you are building workflow (order / task / payment) processing system with the following requirements:
Each workflow con...
New
I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions abo...
New
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
Before I dive in myself, did anyone successfully sprinkle Hologram into their existing LiveView app?
Looking for hints regarding:
Addi...
New
Kia ora,
We have been using elixir-google-api to connect to Google Drive. However, with the updates to Tesla due to CVEs this is now bro...
New
Hi all, I wanted to ask how the community is dealing with post-release steps.
Today we have Ecto migrations, which make sure that the db...
New
Hello,
I have an Elixir backend that implements a custom protocol over TCP. I want to load test the backend and assess the performance o...
New
Other Trending Topics
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve.
They are GUI (Emerge) and State management (S...
New
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #ai
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










Showing Posts 1 to 10- Show Best Posts
- Show All Posts (oldest first)
- Show All Posts (newest first)
krasenyp
You basically need a piece of code which filters the pubsub events based on the currently viewed product. I don’t think theres a much better solution to what you have - using
handle_params. You can subscribe to receive all the pubsub messages of the background jobs and filter inhandle_infobased on the identifier of the currently viewed product. This avoids the unsubscribe/subscribe dance but introduces more messages in the mailbox.garrison
Unfortunately LiveView lacks the primitives needed to perform generalized incremental computation. For example React has
useEffect()anduseMemo(), but Phoenix lacks even a full implementation of the older (inferior) lifecycle paradigm: it hasmount()andupdate(), but nounmount().This makes interop between declarative and imperative code rather… difficult.
Of course you can abandon the incremental approach entirely. The root of the LiveView can subscribe to everything and then meter updates out to individual components.
But now, and this kind-of hints at the problem, the structure of your application has become entirely rigid and static. Yes you can unmount A or B and the messages will be ignored, but you have lost the ability to dynamically subscribe. The ability to dynamically mount/unmount components and incrementalize computation is the fundamental raison d’etre for React-style engines, and LiveView is unfortunately derelict of its duty in this department.
If you’re clever you might think you could transmit subscriptions from dynamically mounted components back up to the root. Believe me, I thought that too. But putting aside for the moment that component ids in Phoenix don’t compose (an unrelated issue), this is still insufficient. You cannot tell if a component has been unmounted, so there is no way for a component to clean up after itself.
Right about now some of you may be getting some ideas about how you might hook into the code that leads to an unmount, upstream, and unsubscribe there. Like at the router level, or in response to an event. Let me stop you right there: you are giving up not only incrementalization, but declarative programming as a whole. You are writing imperative code and will be cursed by the gods. Many stronger than you have ventured down this path, and all have fallen. Abandon hope, all ye who enter here.
To be clear, there is no fundamental or technical reason why LiveView cannot provide this functionality. Instead I think it’s mostly a cultural difference; that is to say, most of the devs using LiveView do not understand or need any of this, and would probably get by just fine with something like HTMX if they didn’t happen to be writing Elixir. I used to think that it would be a good idea to extend LiveView with more incremental functionality, but in reality the depth of the changes needed would likely serve to annoy those who don’t want, need, or understand them in the first place. Plus it’s not like I’m volunteering to do the work.
It will likely be easier to write a new framework from scratch.
(And in general I do think it would be nice to have more app frameworks in Elixir, which is why I’m rooting for Hologram!)
TLDR: No, not really.
krasenyp
I don’t think OP is using live components. They’re probably navigating to the same live view and because it’s in a session, only the
handle_paramscallback is called.Minor aside. Using
sens_updateto update child live components is such a code smell to me, I can’t even start to explain. Please use assigns.garrison
The fact that there is any noticeable distinction between LiveViews and LiveComponents is another unfortunate design wart, but what I wrote still applies if you only have one component (the root LV).
I would love to see you try, but I think there is some misunderstanding here. The code snippet in my post is a PubSub router. It’s not holding state, it’s forwarding messages. Really it’s doing what you suggested above, just extended to components (which cannot receive messages). I do think this is a bad idea, but for much deeper reasons.
longnightElixir
Thank you above two;
Of course, I am not talking about live component; my scenario is just simple case of liveview router/naviagtion.
Now I am considering , to offload these logics into some on_mount hook, to reduce code repeat.
garrison
You really can almost get away with it, though.
Conjuring a reconciler from the void:
It handles
mountandupdatebecausehandle_paramsis called by the engine for both and the reconciler is idempotent. It does not handleunmount, but because this is the root LiveView we get lucky and the PubSub system will throw away our subscription when the LiveView dies.However, we are cheating quite badly. First of all, this trick only works because the root LV always replaces itself. If you were to replace the root LV with another component in the same process (say by navigation), you would be back to square one because there’s no
unmount. Same problem if you tried to use components. The fact that you can get away with this at all is sheer luck, and this solution is a house of cards that will quickly buckle as soon as you add real functionality to your app.Also, notice that we are conveniently running the state through the router. If the
product_idwas a part of the app’s actual state (which serious apps must be able to do, contrary to what many think), there would be no single place to observe changes. Next thing you know you’re writing imperative code again, cursed by the gods, etc.If you’re wondering what a real solution to this problem looks like, here it is:
This is not perfect either because React has warts of its own: for one,
useEffectis not synchronous (and neither isuseLayoutEffect; they lied to you).But it’s certainly a lot better. The function returns a continuation that the runtime can slice properly into the three lifecycle events (
mount,update,unmount) while you get to write code that looks like it’s in the proper order (subscribe first, unsubscribe later). And there’s no messing about with the diff because the runtime has a reconciler built in.tfwright
Seconding @krasenyp , and also would ask, why create a topic for each product rather than have a single “product_jobs” or something topic where the event contains the product id along with whatever metadata about the event, which you can then compare to state of current view, whether LV or whatever?
garrison
Because if you take this to its logical conclusion it won’t end well.
Say you want to add product reviews to your app. Now you’re back where you started: do you want to subscribe to
product_eventsorreview_eventsorreview_events[product_id]or some combination thereof?Applying your strategy again, you could then create a unified
product_and_review_eventstopic and the client can again filter as they wish. Your app gets some more users and the client sure is receiving a lot of events now but it’s probably fine.And then you decide to add “seller updates” to the product page. Okay,
product_and_review_and_update_eventsit is, I guess. Whatever.This happens a few more times, so you finally give in and just rename the topic to
literally_all_events_from_the_entire_database. Every minuscule facet of your app is globally broadcasted to every user. You are essentially streaming the Postgres WAL to every single client in parallel.Unfortunately this will not scale.
You can, by the way, shard your setup in some way such that you can stream all events for a particular shard. For example, if you had a Slack-style app it might be totally reasonable to send the client all events for a given
workspace_id.But, hey, how do you choose which
workspace_idto subscribe to? What happens if the user switches workspaces?And so we have invented the same problem again.
tfwright
Not sure about any of your other hypothetical scenarios–those are not what OP has described and I think it would be prematurely optimizing to handle them in advance (YAGNI). But given the parameters OP has actually described, there’s certainly the tradeoff (already mentioned) that the product view is going to receive more irrelevant messages. Given a high enough number of products actively generating new events, it could create a problem, but personally I’d make that optimization then and not before because, unless you’re Amazon or Temu or whatever, OPs storefront most likely is going to have a fairly constrained number of “active” products at a given time. But my opinion is based on experience dealing with more pain from prematurely (and often poorly) optimized implementations than unperformant ones.
krasenyp
Well, many people have faced this problem and the solutions is to have a piece of code which filters the messages. The live view can have a sidecar process which is subscribed to a few topics and filters, and routes the messages to the live view process.
If more data is needed for some messages, the sidecar can enrich them by calling some internal or external API.