Svelte / Intermediate: Kit routes and server data policy / Lesson 12
Navigation, URL state and targeted invalidation
Represent shareable view state in URLs and rerun the relevant data contract without assuming a universal cache purge.
On this page
Lesson goals
- Explain preloading, goto and tracked load dependencies.
- Keep current page state, invalidation and source freshness distinct.
A shared URL should describe the intended view
Filters, sort order and page cursors often belong in the URL, while temporary focus or an open menu can remain local. A copied client filter that disagrees with the address bar can produce surprising reload and back/forward behavior. Validate path and query input before source access, including repeated parameters. A cursor is a continuation boundary under a data contract, not necessarily a frozen snapshot. Keep private session values out of URLs and logs. Choose whether navigation adds history or replaces it according to the task, and preserve accessible link semantics instead of turning every transition into an opaque click handler.
Target the dependency a load actually declares
The fragment calls invalidate with the same custom dependency label introduced by a server-load example. It is a browser-side Kit navigation API, not a command to purge every external cache. The relevant load must declare or read the dependency under Kitโs tracking rules. A rerun can still return stale data from a source cache, and an unrelated load may not rerun at all. The import and callback were not executed. Use invalidateAll only when its broader current-page behavior is really intended, and review default/custom form-enhancement invalidation separately from manual navigation.
<script>
import { invalidate } from "$app/navigation";
async function refreshCard() {
await invalidate("app:course-card");
}
</script>
<button onclick={refreshCard}>Refresh course card</button>
The matching dependency and browser runtime are prerequisites. No load rerun or cache operation was performed.
Preloading may run work before visible navigation
Link preloading can prepare data before the user commits to a navigation. Keep load functions free of irreversible effects and bound their source cost. goto and link behavior must use approved destinations; an untrusted next parameter can create an open redirect or unsafe URL usage if passed through blindly. Kit may preserve component instances and update data, so do not expect every navigation to rerun initialization. Snapshot or shallow-state features serve particular navigation needs and should not be mistaken for durable storage or server authorization. Verify the selected exact-version behavior rather than assuming all navigation APIs have identical lifetimes.
Define one meaning for repeated filter input
The local parser accepts one state value or a documented default and rejects duplicates. It uses URLSearchParams over synthetic text and makes no request. Another API could allow a list, but every consumer should agree on that shape rather than picking first or last silently. Validation establishes meaning, not permission to see archived courses. A real load should combine the accepted filter with current principal scope and bounded pagination. The test does not exercise Kitโs tracked URL reads, goto history behavior or invalidation; those need a compiled application/browser fixture.
function stateFilter(query){
const values=new URLSearchParams(query).getAll("state");
if(values.length>1)throw new Error("DUPLICATE_STATE");
const state=values[0]??"published";
if(!["published","archived"].includes(state))throw new Error("INVALID_STATE");return state;
}
console.assert(stateFilter("")==="published");
console.assert(stateFilter("state=archived")==="archived");
let rejected=false;try{stateFilter("state=published&state=archived");}catch{rejected=true;}console.assert(rejected);
The default and allowed value pass while repetition rejects. No navigation or source policy is tested.
Test current data, retained drafts and identity transitions
Verify direct load, preloaded navigation, back/forward, targeted invalidation and enhanced-form results under the same route/configuration. Check that current data updates while intentional drafts follow their documented reset/reconciliation rule. After account change, discard incompatible pending results and private cached state. A successful invalidate promise does not prove a database write or global freshness. This course runs only the filter parser; it does not execute navigation hooks, preloading, load dependency tracking, history or source caches. Report those limits and use safe synthetic principals for any real authorized integration rather than testing private live accounts.
Common errors and fixes
A refresh reruns nothing relevant
- Why it happens
- The invalidation target did not match a tracked or declared load dependency.
- How to fix it
- Align dependency declarations and invalidation vocabulary.
- Prevent it next time
- Assert the actual load rerun and displayed source revision.
URL and local filter disagree after back navigation
- Why it happens
- Competing copies of shareable view state had no synchronization contract.
- How to fix it
- Use validated URL state as the intended source or define explicit reconciliation.
- Prevent it next time
- Test shared links, reload and history transitions.
Preload performs a write before a click
- Why it happens
- Rendering/loading contained an irreversible business effect.
- How to fix it
- Move mutation to an explicit validated authorized server action/endpoint.
- Prevent it next time
- Test preload separately from confirmed submission.
Check your understanding
1. Does invalidate guarantee every source becomes fresh?
Show worked solution
No. It targets the documented Kit load dependency behavior. An external cache or source can still return old data, and unrelated representations may not rerun. Name the affected layer, verify its revision and separately repair source invalidation when the domain requires it.
2. Why must preloaded load work remain side-effect free?
Show worked solution
The framework may execute it before the user chooses the destination. A mutation there can occur from hover or visibility and repeat independently of explicit intent. Keep loads for deriving permitted data and use a separate mutation contract with current authority and replay handling.
Key takeaways
- URL state and invalidation need matching explicit contracts.
- Preloading and preserved components change timing, not domain authority.