Invalidate fetched URLs
See original GitHub issueIs your feature request related to a problem? Please describe.
Suppose you were building an e-commerce site. You might have a shopping cart icon in your root src/routes/$layout.svelte
component. Inside src/routes/products/[category]/[id].svelte
you might have an ‘add to cart’ button. When the user clicks the button, the cart icon should update.
One perfectly valid way to model this would be to put the user’s cart on the session
store, and then update the store after the POST triggered by ‘add to cart’ succeeds:
async function submit(e) {
e.preventDefault(); // because we're progressively enhancing the 'add to cart' <form>
const product = await fetch(this.action, {
method: this.method,
body: new FormData(this)
});
$session.cart.products = [...$session.cart.products, product];
}
But you might have valid reasons for not wanting to put that data in session
— perhaps the cart is only visible on some parts of the app and you don’t want to always pay the cost of serializing the data. Instead, you might do something like this:
<!-- src/routes/$layout.svelte -->
<script context="module">
export async function load({ fetch }) {
const cart = await fetch('/cart.json').then(r => r.json());
return {
props: { cart }
};
}
</script>
This creates a problem. POSTing to /cart.json
will add the product(s) to the cart, but will no longer cause the cart icon to update, because the layout component has no way of knowing that the result of fetching /cart.json
has changed.
Describe the solution you’d like
Since we’re using the passed-in fetch
, we know which URLs the layout component depends on. We could therefore expose an API like this:
+// may not be the best place for this functionality, but we can bikeshed that
+import { invalidate } from '$app/navigation';
+
async function submit(e) {
e.preventDefault(); // because we're progressively enhancing the 'add to cart' <form>
const product = await fetch(this.action, {
method: this.method,
body: new FormData(this)
});
- $session.cart.products = [...$session.cart.products, product];
+ invalidate('/cart.json');
}
SvelteKit could straightforwardly keep track of which load
functions fetched the invalidated URL, and rerun them (assuming the components they belong to are still mounted), much as we already do for load
functions that use session
when that store changes value.
Describe alternatives you’ve considered This is a somewhat low-tech solution. A more common approach might be to use a full-blown fat-client state management system that has a copy of the model in memory (see e.g. Firebase). One possibility would be to integrate more closely with such systems or even build one ourselves.
Personally I’m more inclined towards simple, explicit mechanisms that are easy to implement and understand; in any case this would be complementary towards the more full-blown solutions (or at the very least, not in conflict).
Other possibilities that I’m not keen on:
- Intercepting all non-GET fetches and invalidating all
load
functions automatically - Offering a way to invalidate everything in one go, rather than invalidating specific URLs
How important is this feature to you? It’s a nice-to-have — it solves a problem that can already be solved in various ways, but arguably in a more elegant way. And it’s the one feature I’ve seen in Remix that we don’t already have a (more elegant, IMHO 💅 ) equivalent of that I’m aware of 😃
(Their version re-runs all loaders indiscriminately whenever an ‘action’ — their word for POST/PUT/PATCH/DELETE etc requests — takes place. AFAICT it wouldn’t work with external APIs, just the app’s own endpoint. But it does have the nice characteristic that it runs automatically.)
Issue Analytics
- State:
- Created 2 years ago
- Reactions:1
- Comments:10 (6 by maintainers)
Top GitHub Comments
I have a similar use case, we have some pretty complex
fetch
statements we’re making base on the query params on the page, and it’s a pain to have reconstruct the entire query string for eachinvalidate
.Does
invalidate
also updates the URL of the current page? It appears it doesn’t. I have a use case where I would like to share the URL of the page after invalidation. @Rich-Harris @Conduitry