I have a Svelte app with a relatively complex reactivity model. Data for different parts of the app is loaded from an API based on the state of potentially many parts of the UI, and changing one part of that state often requires simultaneous changes to other parts.
A simple example would be a UI with a search box, loaded results, and pagination. If you search for something, click through a few pages of results, and then change your search query, the new results should start back at page 1.
In terms of Svelte stores, results is a derived store with dependencies on writable stores searchText and page:
<script>
import { writable, derived } from 'svelte/store';
let searchEl;
const searchText = writable('');
const page = writable(1);
const results = derived([searchText, page], ([theSearchText, thePage], set) => {
console.log(`calling API with "${theSearchText}", page ${thePage}`);
// network request to API happens here
set([]);
}, []);
function doSearch() {
$searchText = searchEl.value;
$page = 1;
}
function advancePage() {
$page = $page + 1;
}
</script>
<p>
<label>
search text:
<input type="text" on:keyup="{doSearch}" bind:this="{searchEl}" />
</label>
</p>
<p>
(results for page {$page} of "{$searchText}" would go here)
{$results}
</p>
<p>
page: {$page} <button type="button" on:click="{advancePage}">next</button>
</p>
REPL: https://svelte.dev/repl/17ac70e4d4144616aa8af5c01e67a4cc?version=3.50.0
Note what happens in the console if you enter a search term, advance the page, and then search for something else:
calling API with "a", page 1
calling API with "a", page 2
calling API with "a", page 3
calling API with "b", page 3
calling API with "b", page 1
You can see that when the search text is changed from "a" to "b", the derived store triggers an unnecessary update for page 3 of "b".
While this makes perfect sense (nothing in my code says that the updates to the two writable stores should happen simultaneously), it's obviously inefficient and in this case causes an extra network request.
This question from two years ago addresses the same issue, but is phrased terms of how to debounce the update. The only answers involve setting timeouts, which I don't really find satisfactory. Why introduce the delay? What I want to do is prevent the extra store update in the first place.
I know that I could combine searchText and page into a single writable object, but that kind of design pattern isn't going to be sustainable or efficient in my more complicated app.
Is there some standard way of dealing with this? Are there alternatives to the standard Svelte derived store that attempt to address this shortcoming?