Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Signal Equality Functions #562

Open
jeffwcx opened this issue Apr 25, 2024 · 6 comments
Open

Signal Equality Functions #562

jeffwcx opened this issue Apr 25, 2024 · 6 comments

Comments

@jeffwcx
Copy link

jeffwcx commented Apr 25, 2024

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
Copy link
Member

What's the use case?

@jeffwcx
Copy link
Author

jeffwcx commented Apr 25, 2024

Such scenarios are quite common. For example:

  • I only want a few properties in the state to participate in the update:
    signal({ value: '1', __internal: 'xx' }, { equals: (a, b) => a.value === b.value })
  • Sometimes I want to avoid triggering updates for specific values:
    signal(
      { width: 0, height: 0 }, 
       // Do not trigger changes when width or height are zero 
      { equals: ({ width, height }) => !width || !height }
    );

@rschristian
Copy link
Member

rschristian commented Apr 25, 2024

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
Copy link
Contributor

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

@yurivish
Copy link

yurivish commented May 29, 2024

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
Copy link
Contributor

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants