State in URL: the SvelteKit approach

Justin Ahinon
Last updated on
GitHub repository: https://github.com/JustinyAhin/okupter-repos/tree/main/apps/sveltekit-state-in-url
SvelteKit version: 1.16.2
Some context
Last week, while working on a project for the WNBA at my day job, I came across an interesting task. We were building a component that would display some data fetched on the server side. On the frontend, we would have a dropdown that would allow the user to filter the data by a certain property.
The data we were fetching was big enough that we didn’t want to fetch it all at once. Instead, we only fetch on page load a part of it and update the UI every time the user changes the filter.
We were working with Next.js, so I used getServerSideProps
getServerSideProps to fetch the data and some states to keep track of the current filter. To update the data on filter change, I used Next.js router to push a new URL with the new filter as a query parameter. This triggered a new server-side render, and the component was updated with the new data.
While working on this component, I wondered how to do the same thing with SvelteKit.
This blog post is a summary of the approach I’d use to build the same component in SvelteKit.
What I’m going to build
To illustrate the approach, I’m going to build a simple component that displays a list of countries and allows the user to filter them by continent.
I’m using the restcountries API to get the data.
Getting the data on the server
To fetch our data from the server, we're going to use SvelteKit load function. This function is first called on the server on the initial page load and then on the client when navigating to the page.
I wrote a blog post about load functions in SvelteKit here: https://www.okupter.com/blog/sveltekit-internals-load-function
Since we need the data returned to be updated every time the user changes the filter, we need to "make it depends " on whatever we trigger on the client when the user changes the filter. In our case, we're going to use the URL query parameters.
code loading...
If you want to learn more about query parameters in SvelteKit, I also wrote a blog post about it here: https://www.okupter.com/blog/sveltekit-query-parameters
Our load function is pretty simple. It fetches the data from the API and returns it as a prop to the component.
We could have made it a bit more complete by adding some validation in case the user manually enters an invalid region in the URL. Think of something like:
code loading...
Displaying the data
Data table
Since we are returning the data from the server as a prop, we can now display it in our component.
code loading...
Quite straightforward. We just iterate over the list of countries and display them in a table.
Notice that we are not destructuring the data
prop to use countries
directly. This is because data
itself is reactive (whenever it changes on the server, the component will update it). But const { countries } = data
would not be reactive and would only be updated on the initial page load.
Using directly data.countries
might be a bit verbose, but it spares us from having to create another reactive variable to keep track of the countries.
The select dropdown
Now that we have our data displayed let's add a dropdown to filter the countries by continent. This is where the fun begins.
code loading...
The important part here is the handleRegionChange
function. It uses the goto
function from SvelteKit to push a new URL with the new region as a query parameter. This is all we need to trigger a new server-side render and update the data.
Now, we can populate the select dropdown with the list of regions we created earlier and bind its value to the selectedRegion
variable.
code loading...
And that's all we need.
Every time the user changes the region, the server will fetch the data from the API again, and the component will update. The reason why the server can re-fetch the data is because of how SvelteKit handles invalidation. If your load function depends on or references a property whose value has changed, the page will be invalidated, and the load function will be called again.
Note: Read more about invalidation in SvelteKit here: https://kit.svelte.dev/docs/load#invalidation.
Get help with your Svelte or SvelteKit code
Got a Svelte/Sveltekit bug giving you headaches? I’ve been there!
Book a free 15 min consultation call, and I’ll review your code base and give you personalized feedback on your code.
P.S. If you have a bigger problem that may need more than 15 minutes, you can also pick my brain for a small fee. 😊 But that’s up to you!
Conclusion
I like how SvelteKit makes it easy to handle reactive and stateful data. The approach is clean, simple, and very powerful.