Check out a free preview of the full Advanced Elm course
The "Loading & Persisting Data" Lesson is part of the full, Advanced Elm course featured in this preview video. Here's what you'd learn in this lesson:
There are several possible strategies for loading and persisting data between pages. Richard discusses trade-offs between different strategies.
Transcript from the "Loading & Persisting Data" Lesson
[00:00:00]
>> Richard Feldman: So, when I go over here, when I'm loading this page. And I'm loading the free or the global feed or one of these tags, that's doing HTTP request. And while that HTTP request is in flight, we have some decisions to make about what we're going to render on the screen.
[00:00:14]
Likewise, when I refresh the page, at the very beginning, we have a little bit of loading here, so you can see a very brief flash of content as it's coming in there. So what are we actually going to do about the possibility that that loading might take a little bit of time?
[00:00:29]
Well, one thing we talked about earlier was the loading spinner. So we have that concept of wait 500 milliseconds and if we don't have the data loaded by then, display a spinner. But we have a separate question of at what level do we do that. Do we render as much of the page as we can and then only show loading spinners for the parts of the page that are still loading?
[00:00:48]
Or do we just block the whole page and say you know what, until we get all of our data, we're not gonna show you anything? We're just gonna show you at most a loading is there. So I used to do it that second way and I've since come around to the idea that maybe that's not actually the best choice.
[00:01:00]
Maybe the better choice is to load as much as possible, render as much as possible, and then just block waiting for the remaining data to load, which is what we're doing now. So when I load this page, I'm getting two HTTP requests, which we can see inside home.elm or page/home.elm.
[00:01:19]
We could see that right here in the model. So we have tags and feet. Those are the two separate things that we're loading. And we talked about this status type earlier that has loading, loadingSlowly, successfully loaded, or failed. And both of those are loaded at the same time.
[00:01:32]
So when I visit this page, it's loading the feed. And then a separate HTTP request is loading the tags. And as soon as it gets one or the other, it will immediately render it. So basically, this means that if the user's on a slow connection they are getting as much of the screen as possible as soon as possible.
[00:01:48]
But that's not necessarily the right choice for your application. As I said, there are different trade offs here. It may be that what makes the most sense for your application is to wait for all the data sources to come back, because perhaps it doesn't make sense to show the one without the other.
[00:02:00]
Depending on your use case, you may want to actually intentionally block, and in that case, you would actually organize this in your data model perhaps a little bit differently. Or at least in your view where you would check to make sure that both of these were present before continuing on.
[00:02:14]
Lots of different ways you can do it. Okay, then we have the final question of persistence. So what is actually going to be shared between pages? So we have a couple of different examples of this. One is we are on this page, and when I go to different pages, I wanna keep my session around in memory.
[00:02:35]
So we talked earlier about having one single source of truth for the session, which is ultimately a cache of what's in local storage, which in turn is a cache of what's on the server. But we do in fact have that cache in our model, and so we have this notion of a session, which is data that is essentially shared between pages.
[00:02:51]
This is a cache that gets handed around from page to page, and if we are logged in, we have the navigation key. Which is an implementation detail of navigation that we're not gonna get into in this workshop. And then we have the viewer if we're logged in. And that just gets passed around from page to page, and the viewer contains among other things, the authentication token.
[00:03:14]
So, that prevents us from having to go and get that from the server or some local storage each time we transition from page to page. But that notion of caching that session from page to page can happen in all sorts of different ways. For example on the package website, when you go from one page to another, it's actually caching the search results from the previous page.
[00:03:34]
So if I go to package website, when I go from one link to another, it's able to cache the search results that I had previously sourced. If I go back, it doesn't need actually go back and do another HTTP request to show these search results. It actually just remembers them and cache them as it was transitioning from page to page in this single page application.
[00:03:53]
So essentially, you can cache whatever you want from page to page and you can say, yeah, we don't need to do another HTTP request. I'm quite confident that these are the search results that you want and the odds of your getting, missing search results are so low that I'd rather just show you them faster.
[00:04:08]
But then once again, we have caching is a hard problem. Cache and validation is a hard problem. Now you have questions like should you have a timeout on your cache? Should you say I will keep these in my cache for this period of time. But once a certain number of milliseconds, or seconds, or minutes has elapsed.
[00:04:23]
You know what, it's probably stale, you've probably left that tab open for a long time. Now we need to validate that cache and say let's go do an HTTP request as if we've loaded the page fresh. So all of these things are options, and they're worth considering based on your particular use case.
[00:04:37]
What things do you want to load? When do you want to load them? What should the user be able to see while they're loading? And once you've loaded them, how do you want to persist them across pages? Do you want to persist them at all? Do you want to go get a fresh copy every time, or do you want to save some of the stuff in a cache?
[00:04:50]
If you're gonna save it in a cache, do you wanna invalidate it? If so, when, under what circumstances? All of these things are tradeoffs worth considering when building a single page application. So we talked about routes and how they can go from URL to route, we have that mapping.
[00:05:04]
We talked about pages, how we have, sorry, routes can also go from the particular route that you already have to the URL. We talked about pages, which is the notion of a particular page that you're viewing in the browser. Which is related to routes but not on a one to one basis.
[00:05:19]
And also the page module holds on to the view that is used on all the pages for rendering the frame around each page. As well as the extra logic for viewing errors, which a lot of pages had to used. Let's talk about loading and persisting data about when we should go to the server to get more information and when we should come back and what we should store in the cache, if anything.
[00:05:40]
If we do decide to store something, how we should go about persisting that, whether the cache should expire under a certain policy. And finally, we talked about module structure, like when to put things in a namespace. The potential downsides of having a namespace like data or request or something that encourages putting modules in a particular boundary.
[00:05:56]
Even when perhaps there's a better boundary to be had by focusing on a type, which tends to be the better policy with Elm. So far, the only namespace that I've consistently found use for is page.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops