paoloricciuti / sveltekit-search-params

The easiest way to read and WRITE from query parameters in sveltekit.
https://sveltekit-search-params.netlify.app
MIT License
443 stars 10 forks source link

Svelte 5 support #80

Open paoloricciuti opened 1 month ago

paoloricciuti commented 1 month ago

Svelte 5 is right around the corner and while stores are still supported i want to upgrade this library to take advantage of runes.

This however require some changes that are not back compatible so my plan is to continue supporting stores in sveltekit-search-params@^2 and upgrade to runes in sveltekit-search-params@^3.

The new version however will likely face some api changes because of how runes behave.

queryParameters

The function queryParameters will benefit a lot from runes: today this function return an unique store object with each query parameter as the key.

<script>
    import { ssp, queryParameters } from "sveltekit-search-params";
    const params = queryParameters({
        search: ssp.string(),
    });
</script>

<input bind:value={$params.search} />

with runes the syntax will not change that much but the updates should be much more fine grained which is good

<script>
    import { ssp, queryParameters } from "sveltekit-search-params";
    const params = queryParameters({
        search: ssp.string(),
    });
</script>

<input bind:value={params.search} />

queryParam

Here's where the change will be much more intensive so first thing first sorry if you are using this intensively...i'll try to see if i can create a migration CLI to help you with your upgrade.

Today queryParam accept the key of the query parameter as input and returns a store with that param by itself. If the query parameter is a string the store will contain the string itself.

<script>
    import { ssp, queryParam } from "sveltekit-search-params";
    const search = queryParam("search");
</script>

<input bind:value={$search} />

This is not possible with runes so we have three options:

The boxed value

The simplest option would to return a ref or a boxed instead of the actual value. The downside is that you need to access it with .value everywhere.

<script>
    import { ssp, queryParam } from "sveltekit-search-params";
    const search = queryParam("search");
</script>

<input bind:value={search.value} />

This is simple to refactor but once you need to access it with .value everywhere is it really worth it over using queryParameters with a short name and just access it like qp.search everywhere?

The function

Another option could be have the returned value be a function...you could access it by calling it and set it by calling it with a typesafe parameter.

<script>
    import { ssp, queryParam } from "sveltekit-search-params";
    const search = queryParam("search");
</script>

<input value={search()} oninput={(e)=>{search(e.target.value)}} />

this is nice to see but it can get complex with Typescript type narrowing and it get's pretty hairy with objects and arrays.

The derived

A somewhat nice option would be to make use of $derived.by to destructure the return value of queryParam. This would give us a simple value to use everywhere and we could even return an input object to spread into your inputs that automatically set the oninput property to mimic the bind behaviour.

<script>
    import { ssp, queryParam } from "sveltekit-search-params";
    const [search, inputsearch, setsearch] = $derived.by(queryParam("search"));
</script>

<input {...inputsearch} />
The search is {search}

but this again become very hairy with object and arrays (especially if you want to bind a property of that object instead of the whole object).

Conclusion

I'm not really satisfied with any of the options for queryParam and i wonder if we should just drop that api but i would love to have YOUR opinion and ideas on this.

Hugos68 commented 1 month ago

Here is a bit of a crazy take, why don't you remove queryParam from the API. Just read the conclusion, it's like you're reading my mind! But yeah, I think having 2 ways to do the same thing only hurts in any API. I also don't see the benefit. If all examples use qp as the variable I am A-ok with using qp.<my-value> since they're using $state it should be fine grained and thus not cause any unwanted updates correct?

stolinski commented 1 month ago

I agree with @Hugos68 i don't think it's needed.

lucaswalter commented 1 month ago

I'm currency using the syntax const search = queryParam("search"); but to be honest, I wasn't aware of the other approach. I like the benefits of having more fine-grained control and it would be very simple for us to switch over to when we upgrade to svelte 5.

<script>
    import { ssp, queryParameters } from "sveltekit-search-params";
    const params = queryParameters({
        search: ssp.string(),
    });
</script>