preactjs / signals

Manage state with style in every framework
https://preactjs.com/blog/introducing-signals/
MIT License
3.82k stars 95 forks source link

Signal Equality Functions #562

Open jeffwcx opened 7 months ago

jeffwcx commented 7 months ago

Can we add some parameters to the signal for comparing signal values? Currently, the default comparison is simply ‘===’. Perhaps we can refer to Angular signals and allow users to define their own equality functions?

rschristian commented 7 months ago

What's the use case?

jeffwcx commented 7 months ago

Such scenarios are quite common. For example:

rschristian commented 7 months ago

I don't think they're that common, given the is the first request for it on this repo ;)

Personally, I'd say you're better off with a different data structure that wraps the values you want in signal(), keeping those values you don't want tracked outside of it. As for "avoid triggering updates", IMO, that goes against the very idea of a reactive container.

That said, adding a comparator method to the signal prototype should probably be workable.

XantreDev commented 6 months ago

It's possible to implement signal with comparsion in user land. Maybe I will make an implementation

yurivish commented 6 months ago

I've come across a few cases where it would be useful to control whether a signal is considered to be changed when its value is set. These have all been for the sake of improved performance in situations when your signal holds an object that is expensive to construct, but might change over time in response to other signals, and you want those changes to propagate through the signal graph even though the object is the same (comparing with ===).

As a concrete example:

A common pattern in data visualizations is to use dynamic scales, which map between the data domain and the visual domain. For example, a linear scale might be used to determine bar widths in a bar chart. You might want a reactive scale that adjusts to changes in the width of the chart without requiring the creation of an entirely new scale object with each change in the dependencies. But if you put a linear scale object into a computed signal, there's no way to "in-place update" the properties of that object when the width changes, since the update will not be propagated forward.

A similar use case is when there you want to reduce the number of allocations by mutating an object in place but treating it as changed. For example, in a game engine UI context you may have objects representing 2d or 3d vectors (eg. colors or positions) that might want to update every frame while the user is interacting with eg. a color picker, without causing a new allocation for each update to each property.

XantreDev commented 6 months ago

You can use deepReactivity in these cases I've ported Vue deep tracking system to preact signals, so you can use it this way