proposal-signals icon indicating copy to clipboard operation
proposal-signals copied to clipboard

`Signal.State.prototype.update` to update values using callbacks

Open Ocean-OS opened this issue 11 months ago • 6 comments

When using signals, often the value of a signal is not known, but a change needs to be made based on the current value. This pattern can be found in Svelte's stores, Solid's Signals, and React's useState, to name a few. This pattern leads to cleaner code with less clutter. Since using a callback in Signal.State.prototype.set is too ambiguous (setting the value to a function might be the preferred operation), it seems reasonable to add Signal.State.prototype.update. Here's some examples of how the update function would work:

let count = new Signal.State(0);
function increment() {
    count.update(c => c + 1);
}
function createCountdown(start, duration) {
    let countdown = new Signal.State(start);
    let interval = setInterval(()=>{
        countdown.update(c=> c - 1);
        if (countdown.get() === 0) clearInterval(interval);
    }, duration/start);
    return countdown;
}

function createTypewriter(text) {
    let typewriter = new Signal.State("");
    let chars = text.split('');

    function type(char) {
        return function() {
            typewriter.update(t => t + char);
        }
    };
    for (let index = 0; index < chars.length; index++) {
        setTimeout(type(chars[index]), 200 + index * 200);
    }
    return typewriter;
}

Ocean-OS avatar Dec 24 '24 23:12 Ocean-OS

can you describe the situation in which the value can't be known? I don't understand

let known = count.get()

NullVoxPopuli avatar Dec 25 '24 00:12 NullVoxPopuli

can you describe the situation in which the value can't be known? I don't understand

let known = count.get()

By known, I mean a case where the developer can't just do this:

count.set(42); //or any other constant value

...because the value could be acquired through user input, fetching, etc. The update function is primarily a cleaner way to do:

let updater = c => c+1;
count.set(updater(count.get()));

Ocean-OS avatar Dec 25 '24 02:12 Ocean-OS

...because the value could be acquired through user input, fetching, etc.

sorry I still don't understand this

is primarily a cleaner way to do

this I understand (and am ok with, tbh) -- but I'd like to know what " user input, fetching, etc." patterns need the updater. I feel like I'm missing something :\

sorry im dense!

NullVoxPopuli avatar Dec 25 '24 05:12 NullVoxPopuli

this I understand (and am ok with, tbh) -- but I'd like to know what " user input, fetching, etc." patterns need the updater. I feel like I'm missing something :\

sorry im dense!

I meant like something where you'd have to use count.get() instead of a constant value, apologies for the bad explanation. Example:

count.set(42); //constant ("known") value
count.set(count.get() + 1); //not "known" value

Ocean-OS avatar Dec 25 '24 05:12 Ocean-OS

The point of the callback form is that it access its value, to set a new one, without causing tracking, this is the request https://github.com/tc39/proposal-signals/issues/92 , but that doesn't mention a new method update which is requested here. For whatever reason, the other issue was just closed. @jkup

titoBouzout avatar Jun 24 '25 14:06 titoBouzout

The point of the callback form is that it access its value, to set a new one, without causing tracking, this is the request #92 , but that doesn't mention a new method update which is requested here. For whatever reason, the other issue was just closed. @jkup

Sorry! Just trying to clean through old issues, I misunderstood #92 - thank you for explaining!

jkup avatar Jun 25 '25 14:06 jkup