Can LV work for apps with low interactivity and spotty connections?

Hi! I have a decent amount of work experience with Elixir, but mainly on an API, so no direct experience with LV yet, aside from some experimenting.

I have on my hands a Laravel+Inertia project that needs to be rewritten and I’d like to migrate to Elixir. I know Inertia is available for Phoenix too, but I’m trying to understand if LiveView can work for this use-case.

The TLDR is:

  • is LV a good choice for an app that has some interactivity, but does not require frequent or live updates?
  • assuming frequent disconnects, is there any resource on how to provide a good UX? I could not find any.

Now some more details :grinning_face:

The target audience is largely going to connect from their smartphone. The main page of this app has some interactions with live search and filters, a resulting infinite scroll list for loaded data, and small interactions here and there though buttons on each item that open pop-ups with extra details, loaded when the pop-up opens. Nothing special. There’s more but this is the relevant bit for my questions.

Disconnects are, at least in my area, somewhat frequent. Think entering into a store and having low signal. This is very much relevant since this app let’s you search info about products and is likely to be used in that exact scenario.
There is enough to navigate but not enough for a stable, uninterrupted, websocket connection.

This causes LV to rebuild it’s server side state on reconnect, and in some cases it could happen every 20-30 seconds. Reconnects also happen when reopening the browser from the background, at least on iOS. Other reasons could be deployments of new versions of the app.

I’m working on a demo and solved some of the problems by taking inspiration from this blog post: https://fly.io/phoenix-files/restore-liveview-state-on-startup/ and adapting it to my use-case. It works (ish) but this still produces unwanted flashes/reloads for the user.

I’ll give an example: the infinite scroll list. It seems quite difficult to get the current page to reload while keeping the scroll position intact.
What I have a hook that saves the current page on scroll. This is sent on reconnect, and only that page is reloaded so that the user at least starts from the correct page.
However this still produces a jump since the exact scroll position relative to the page is lost and a flash is visible for the data being reloaded. I’m mitigating with an AsyncResult so that there’s at least a clean transition, but there is still a transition from “list of elements → loading → same list of elements”. With disconnects this frequent, a large amount of time is also spent on reloading the exact same data. I don’t mind an extra query but the user should not have to see loading states for something that is already loaded on the page.
This is not a critique, I’m 100% sure it’s a skill issue. I feel like I’m fighting the framework and that generally means I’m doing something wrong, but I couldn’t find any up to date examples or documentation on how to accomplish this and it seems I can’t quite get there on my own.

This brings me to the second item on my list: . None of this is really “live”, as in a live stock graph would be, or a live editor with multiple users would be.
Whatever has been loaded on the page is already an ok state and LV replaces a frontend+API situation.

I’ve been trying (and failing :sweat_smile:) to work around this by seeing if I could completely ignore a reconnect re-render, and just use the LV connection to send-receive responses like HTTP would.
This seems intuitively wrong (and not possible) as I see that LV re-renders on state changes (similar to React), but if the LiveView process holds the state and if it dies with a disconnect than the state has to be re-built and it could be completely different from before (not in this case, but conceptually). So I thought I could try to cache the state in a way that survives a disconnect, either by keeping a local copy on the client or somewhere on the server like an ETS table.
This shows some promise and I have a super basic version working, but this seems complex and while it solves the getting the correct data problem, it does not solve the showing loading states while reloading the same information problem.

Again, this is not a critique, I’m sure it’s a skill issue on my part. It just that these seem like fairly common use-cases and I’d like to learn how to properly implement them in LiveView.
If not I’m perfectly happy to keep using Inertia and plain old controllers, but LV is kinda cool and fun to use so I’d love to be able to make it work.

2 Likes

Does the whole thing need to be rewritten, or just the back end?

It needs to be rewritten from scratch. But the point is not to pick what’s convenient, that would be Inertia because I know it already and none of what I highlighted would be a problem. That’s my plan B and it’s safe.
However LV is a first party solution and this is a learning experience. If the problems I highlighted can be cleanly solved in LiveView I’m happy to use it. I just want to understand better how to solve this because it would be a common occurrence.

Is it work or your personal project? For work I would always pick the boring path.

If it is for your personal project, then follow your heart. You don’t need anyone to explain the pros and cons, because whatever we say will not sink in anyway. Do it, and you will either overcome the hurdle (great) or learn from your failure (greater still)

1 Like

It’s for work but this is also a benchmark to decide if we can use LV in the future instead of React.

I’d like to make a technical decision, so I’m looking for any kind of resource on people who had similar problems and how they were solved.
Or a high level explanation from someone who had similar issues. Anything remotely technical, really :joy:

how about keep react client and use phoenix.sync Phoenix.Sync — Phoenix.Sync v0.4.3

Thanks but as I said I’m not looking for alternatives, I already have no problems making it work with React!

I think I was just unclear with my questions, english is not my first language :upside_down_face:

I’m only looking for an explanation/blog post/example repo/discussion about how to manage non trivial state restoration with frequent disconnects in LiveView and LiveView only, without disrupting the user experience with stuff flashing and jumping around on the screen.
The main example I’m interested about is infinite scroll lists. There are other cases but the logic would be similar, so I’d rather focus on this example.

As I’ve pointed out in the original post, I have some partial solutions I’ve worked out, but it seems like way too much work and way too convoluted for a common scenario, hence me asking for help because I don’t know what I’m missing.

I haven’t read through the whole fly article, but using hooks there is no way… or at least very hard… to avoid the flash. With state being stored on the server and tied to the DOM, JS hooks are always going to run after the initial sync. You’ll have a far easier time if you store all of your paging and filter parameters in the URL, that way you can reconstruct your state before the DOM loads.

LIbraries like Flop and Flop.Phoenix do this for you though it’s not super hard to do it yourself.

With that being the case then LiveView doesn’t seem like what you want. The design of LiveView is such that the client state is a real-time representation of a live backend. If you don’t want that then LiveView isn’t the best choice. There are creative ways around it but it’s ultimately working against LV (at least the LV at the time of my writing this) and you are running into the pains of doing so. I think you’d have a better time with React + Phoenix as a backend which would still allow you to take advantage of Phoenix/Elixir/BEAM.

Although before giving up I would try storing state in the URL which to me is just good practice regardless of the tech you are using.

1 Like