Skip to content

Assume every variable might be dynamic and therefor render all of them inside a render_effect(). #11016

Closed as not planned
@Evertt

Description

@Evertt

Describe the problem

This is actually a smaller feature request that I'm asking for, in case #11014 for some reason won't get accepted. Please first check out #11014, because I care more about that one and if that one gets accepted then this one will be moot.

My frustrations are actually about how Svelte 5's current design makes it impossible for us (the community) to expand on Svelte's primitives (i.e. its runes / underlying signals), creating more primitives that offer the same ergonomics as Svelte 5's native primitives, like being able to do this:

let count = $state(0)

function increment() {
    count = count + 1
}

Instead of:

<script lang="ts">
const count = ref(0)

function increment() {
    count.value = count.value + 1

    // or as some people prefer
    // count(count() + 1)
}
</script>

<button onclick={increment}>
    The count is at {count.value}
</button>

But unfortunately, for us who want to create entire libraries full of novel reactive utilities, similar to VueUse and Solid Primitives... We have no choice but to use one of those less ergonomic syntaxes.

Fortunately though, there is a solution that could solve almost all the ergonomic problems. Namely, if our ref() could return an object that includes methods such as toString() and valueOf() and [Symbol.toPrimitive](hint), then there are many cases in which we could treat count as if it were simply the primitive value that it is wrapping.

It doesn't fully fix the mutating scenario of a ref wrapping a primitive value. Which is why, again, I hope that #11014 will get accepted. But in any case it should fix almost all of the reading scenarios. For example, one could rewrite increment to this:

function increment() {
    count.value = count + 1
    // or count(count + 1)
}

And one should be able to simply use {count} anywhere in the template and it should simply print out the primitive value wrapped by count, thanks to those methods we added to the object.

However, that does not always work! Because currently Svelte tries to make educated guesses about which values might be reactive and sometimes it will guess (incorrectly!) that a value is probably not reactive and then it will render that value in the template outside of a render_effect(), which will make it not reactive.

Describe the proposed solution

Simple, just assume any variable might be reactive, because you simply can't know for sure.

In the worst case scenario, if the variable is indeed not reactive, you lose a tiny bit of performance on the first render (because of the overhead of render_effect()). But after that it won't have any effect on anything whatsoever, because the non-reactive value will never change and so the render_effect() will never re-run.

But that will give us, the community, the opportunity to create ref() functions that return reactive things that use all the tricks we can think of to make the ergonomics of using those reactive things the best we can make them.

Importance

nice to have

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions