Skip to content

eager option for signals #83

@WebReflection

Description

@WebReflection

I am fully aware the philosophy of signals should be "once ref changes, effect out there" but there are cases that drive signal reactivity, without ever being involved in such reactivity ... let me expand on that:

const rawData = [];
const data = signal(rawData);

// this drives changes but it doesn't want/need to create a new
// array holding potentially 1000 things in `data`
document.querySelector('.my-thing').onclick = (event) => {
  const { dataset } = event.currentTarget;
  rawData[+dataset.id] = dataset.value;
  data(rawData);
};

// here the effect that should react on '.my-thing' click
effect(() => {
  const target = document.querySelector('.my-target');
  for (const value in data()) {
    // do something in there
  }
});

So, the target effects on data changes but data changes shouldn't be sliced or copy because other parts in the stack might be involved and have reference to that very same data for other reasons ... accordingly, could we add an eager = false extra option (or even an option property for future sake such as signal(value, { eager: true })) so that update for both computed and signals could return true whenever it's explicitly intentional to trigger updates on mutable data changes ???

Performance are an issue but also reference fan-out when in some scenario one doesn't want-need to react to any data change but would like to drive reactivity through such shared data, like it is for my .my-thing click example.

That means that at least updateSignal https://github.com/stackblitz/alien-signals/blob/master/src/index.ts#L200C10-L203 should do instead:

function updateSignal(s: Signal, value: any): boolean {
	const { previousValue } = s;
	s.flags = 1 satisfies ReactiveFlags.Mutable;
	s.previousValue = value;
	return s.eager || (previousValue !== value);
}

That also aligns with the current logic because you do (while returning) s.previousValue !== (s.previousValue = value) which invokes explicitly a set operation indeed, but nobody can decide how that set operation could react.

Thanks for considering or expanding around these choices, my proposal feels easy to implement and it'd improve a lot use cases around signals, yet I am sure you have opinions or reasons for not wanting such proposal in here and I'm happy to hear or learn about it 👋

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