sveltekit-search-params
Advanced tools
Comparing version 2.0.0 to 2.1.0
{ | ||
"name": "sveltekit-search-params", | ||
"version": "2.0.0", | ||
"version": "2.1.0", | ||
"repository": "git+https://github.com/paoloricciuti/sveltekit-search-params.git", | ||
@@ -5,0 +5,0 @@ "author": "Paolo Ricciuti", |
@@ -7,3 +7,3 @@ import { type Writable } from 'svelte/store'; | ||
}; | ||
export type StoreOptions = { | ||
export type StoreOptions<T> = { | ||
debounceHistory?: number; | ||
@@ -13,2 +13,3 @@ pushHistory?: boolean; | ||
showDefaults?: boolean; | ||
equalityFn?: T extends object ? (current: T | null, next: T | null) => boolean : never; | ||
}; | ||
@@ -55,4 +56,4 @@ type LooseAutocomplete<T> = { | ||
}; | ||
export declare function queryParameters<T extends object>(options?: Options<T>, { debounceHistory, pushHistory, sort, showDefaults, }?: StoreOptions): Writable<LooseAutocomplete<T>>; | ||
export declare function queryParam<T = string>(name: string, { encode: encode, decode: decode, defaultValue, }?: EncodeAndDecodeOptions<T>, { debounceHistory, pushHistory, sort, showDefaults, }?: StoreOptions): Writable<T | null>; | ||
export declare function queryParameters<T extends object>(options?: Options<T>, { debounceHistory, pushHistory, sort, showDefaults, equalityFn, }?: StoreOptions<T>): Writable<LooseAutocomplete<T>>; | ||
export declare function queryParam<T = string>(name: string, { encode: encode, decode: decode, defaultValue, }?: EncodeAndDecodeOptions<T>, { debounceHistory, pushHistory, sort, showDefaults, equalityFn, }?: StoreOptions<T>): Writable<T | null>; | ||
export {}; |
@@ -47,2 +47,7 @@ /* eslint-disable @typescript-eslint/no-empty-function */ | ||
} | ||
function isComplexEqual(current, next, equalityFn = (current, next) => JSON.stringify(current) === JSON.stringify(next)) { | ||
return (typeof current === 'object' && | ||
typeof next === 'object' && | ||
equalityFn(current, next)); | ||
} | ||
export const ssp = { | ||
@@ -110,4 +115,5 @@ object: (defaultValue) => ({ | ||
const debouncedTimeouts = new Map(); | ||
export function queryParameters(options, { debounceHistory = 0, pushHistory = true, sort = true, showDefaults = true, } = {}) { | ||
export function queryParameters(options, { debounceHistory = 0, pushHistory = true, sort = true, showDefaults = true, equalityFn, } = {}) { | ||
const overrides = writable({}); | ||
let currentValue; | ||
let firstTime = true; | ||
@@ -168,3 +174,3 @@ function _set(value, changeImmediately) { | ||
} | ||
const { subscribe } = derived([page, overrides], ([$page, $overrides]) => { | ||
const { subscribe } = derived([page, overrides], ([$page, $overrides], set) => { | ||
const [valueToSet, anyDefaultedParam] = mixSearchAndOptions($page?.url?.searchParams, $overrides, options); | ||
@@ -174,3 +180,7 @@ if (anyDefaultedParam && showDefaults) { | ||
} | ||
return valueToSet; | ||
if (isComplexEqual(currentValue, valueToSet, equalityFn)) { | ||
return; | ||
} | ||
currentValue = structuredClone(valueToSet); | ||
return set(valueToSet); | ||
}); | ||
@@ -193,5 +203,6 @@ return { | ||
}; | ||
export function queryParam(name, { encode: encode = DEFAULT_ENCODER_DECODER.encode, decode: decode = DEFAULT_ENCODER_DECODER.decode, defaultValue, } = DEFAULT_ENCODER_DECODER, { debounceHistory = 0, pushHistory = true, sort = true, showDefaults = true, } = {}) { | ||
export function queryParam(name, { encode: encode = DEFAULT_ENCODER_DECODER.encode, decode: decode = DEFAULT_ENCODER_DECODER.decode, defaultValue, } = DEFAULT_ENCODER_DECODER, { debounceHistory = 0, pushHistory = true, sort = true, showDefaults = true, equalityFn, } = {}) { | ||
const override = writable(null); | ||
let firstTime = true; | ||
let currentValue; | ||
function _set(value, changeImmediately) { | ||
@@ -244,5 +255,9 @@ if (!browser) | ||
} | ||
const { subscribe } = derived([page, override], ([$page, $override]) => { | ||
const { subscribe } = derived([page, override], ([$page, $override], set) => { | ||
if ($override) { | ||
return $override; | ||
if (isComplexEqual(currentValue, $override, equalityFn)) { | ||
return; | ||
} | ||
currentValue = structuredClone($override); | ||
return set($override); | ||
} | ||
@@ -254,5 +269,14 @@ const actualParam = $page?.url?.searchParams?.get?.(name); | ||
} | ||
return defaultValue; | ||
if (isComplexEqual(currentValue, defaultValue, equalityFn)) { | ||
return; | ||
} | ||
currentValue = structuredClone(defaultValue); | ||
return set(defaultValue); | ||
} | ||
return decode(actualParam); | ||
const retval = decode(actualParam); | ||
if (isComplexEqual(currentValue, retval, equalityFn)) { | ||
return; | ||
} | ||
currentValue = structuredClone(retval); | ||
return set(retval); | ||
}); | ||
@@ -265,3 +289,2 @@ return { | ||
update: (updater) => { | ||
const currentValue = get({ subscribe }); | ||
const newValue = updater(currentValue); | ||
@@ -268,0 +291,0 @@ _set(newValue); |
@@ -11,4 +11,2 @@ # sveltekit-search-params | ||
![npm bundle size](https://img.shields.io/bundlephobia/minzip/sveltekit-search-params) | ||
![npm](https://img.shields.io/npm/v/sveltekit-search-params) | ||
@@ -425,2 +423,24 @@ | ||
### equalityFn | ||
While this is not a problem for primitive values if your store has a complex object or an array (or if you are using `queryParameters`) as a value even if the reference is the same svelte will trigger reactivity for it. To provide you with optimistic updates there's the possibility that the store will change multiple times during a single navigation. To fix this problem by default we check if the value of the store is the same by using `JSON.stringify` so that if the overall shape of your store is the same we avoid triggering the reactivity. | ||
This is fine for most cases and you will likely never touch this option but if you have some use case not covered by `JSON.stringify` you can specify the option `equalityFn`. This option is a function that takes the `current` value and the `next` value as parameters and need to return a `boolean`. You should return `true` from this function when the value of the store is unchanged (according to your own logic). This will not trigger reactivity (note that the navigation will still happen). | ||
For `queryParameters` the equality function applies to the entire store (so make sure to check that every query parameter is exactly the same before returning `true`). | ||
```svelte | ||
<script lang="ts"> | ||
import { queryParam, ssp } from 'sveltekit-search-params'; | ||
const pageNum = queryParam('pageNum', ssp.object<{ num: number }>(), { | ||
equalityFn(current, next) { | ||
return current?.num === next?.num; | ||
}, | ||
}); | ||
</script> | ||
``` | ||
NOTE: the equality function will not be used on primitive values, hence you can't pass the equality function to stores that have a primitive type. | ||
### How to use it | ||
@@ -427,0 +447,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
38599
589
488