signals icon indicating copy to clipboard operation
signals copied to clipboard

Notifying signal update with reference types

Open tzakharko opened this issue 1 year ago • 4 comments

A signal will only fire if a "new" value is assigned. So if I use a signal with a reference type, e.g. an array, updating the value will not actually fire the signal. Cloning works but sounds wasteful. It would help if there were a way to fire a signal manually after update in this case.

tzakharko avatar Oct 09 '22 18:10 tzakharko

If you want to handle references, I think it's best to use immutable data structures. That does not involve full cloning but only 'recreate' the required parts of your data structure.

KnisterPeter avatar Oct 13 '22 07:10 KnisterPeter

@KnisterPeter this still means making shallow clones for dictionaries. Unfortunately, JavaScript is not very good at immutability. I mean, it's not a big deal and a clone on user interaction won't even be measurable, but it does make the code more awkward.

tzakharko avatar Oct 14 '22 08:10 tzakharko

Signals use versioning internally, each update increases a version number, so the value isn't really used to know if a computed or effect should update.

With that in mind, you can create your own abstractions using the exact same idea:

function refSignal<T>(value: T) {
	const version = signal(0);
	const notify = () => version.value++;

	return {
		notify,
		get value() {
			version.value; // Subscribe
			return value;
		},
	};
}

We create a signal version for the sole purpose of allowing other computed or effect to subscribe to it. It's value can be anything but a number is pretty cheap so that'd work just fine:

const s = refSignal(["hello"]);

effect(() => {
	console.log("Current value:", s.value);
});

s.value.push("World!");
s.value.push("!!!");
s.notify();

// Effect logs:
// Current value: [ 'hello' ]
// Current value: [ 'hello', 'World!', '!!!' ]

eddyw avatar Oct 14 '22 19:10 eddyw

@eddyw thanks for the suggestion, that’s very similar to the interim solution I am currently using, only I use a Boolean and invert it every time to avoid dealing with overflows (probably will never happen in practice but better safe than sorry)

tzakharko avatar Oct 14 '22 19:10 tzakharko