-
Notifications
You must be signed in to change notification settings - Fork 88
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
feat: add effectOnceIf helper function #419
Conversation
Hello @lorenzodianni |
Hi @eneajaho, Suppose we have a task management application where each task has a progress state that ranges from 0% to 100%. We want to trigger an alert (e.g., display a notification or log a message) when a task's progress exceeds 75% for the first time. Once this alert is triggered, it should not trigger again, even if the task's progress continues to increase. @Component({})
class TaskProgress {
// Declare a signal for the task's progress
progress = signal(0);
// Use effectOnceIf to trigger an alert when progress exceeds 75%
effectOnceIfRef = effectOnceIf(
// Condition: if progress exceeds 75%
() => this.progress() > 75,
// Execution function: triggers the alert once
(valueReturnedFromCondition, onCleanup) => {
console.log(`Alert: Progress has exceeded 75%! Current value: ${this.progress()}%`);
onCleanup(() => console.log('Cleanup after alert'));
});
}
// Update the task's progress
taskProgress.progress.set(50);
// -> nothing happens
taskProgress.progress.set(80);
// -> log: Alert: Progress has exceeded 75%! Current value: 80%
// -> log: Cleanup after alert
taskProgress.progress.set(90);
// -> nothing happens Perhaps @lorenzodianni has other use cases. |
Hi @eneajaho
Here are some real use cases: effectOnceIf(
() => this.mapRenderer.isMapReady() ? this.markers() : false,
(markers) => this.mapRenderer.addMarkers(markers),
); effectOnceIf(
() => {
const myDomEl = this.myDomEl();
return myDomEl && this.canInitializeMyDomLib() ? myDomEl : false;
},
(element) => {
new MyDomLib(element, {...});
},
); effectOnceIf(
() => this.userHasAcceptedGeolocationPermissions() ? this.getCurrentPosition() : false,
(position) => this.mapRenderer.centerMap(position),
); And of course, the use case mentioned by @nemu69 could be another one |
I think for most cases it might make sense to use a countGreaterThanThree = computed(() => this.count() > 3);
effect(() => {
if(this.countGreaterThanThree()){
// do whatever
}
}) But I can see the use case where you wouldn't want the Perhaps an alternative to consider would be some sort of "trigger" or "tripwire" signal that, once it becomes countGreaterThanThree = computedUntilTrue(() => this.count() > 3);
effect(() => {
if(this.countGreaterThanThree()){
// do whatever
}
}); At least to me an API like this feels more idiomatic. |
Hi @joshuamorony, countGreaterThanThree = computedUntilTrue(() => this.count() > 3);
effect(() => { // <--- a normal effect that should fire on each signal changes, but not in this case
if(this.countGreaterThanThree()){ // <--- it looks like a regular signal, so I have no information indicating that it will fire only once. To understand its actual behavior, I need to read the signal's definition
//...
}
}); That's why I suggested a slightly different syntax, so everything remains scoped and understandable at first glance when reading it: effectOnceIf( // <--- I can immediately tell it's not a normal effect and understand its actual behavior.
() => this.count() > 3, // <--- condition
() => { // <--- execution
// do whatever
}
) |
I'd like to propose this helper function, I'm open to implementing improvements and making changes as needed 🙌
I'm not sure about the name, so suggestions are appreciated 🤔
effectOnceIf
It is an helper function that allows you to create an effect that will be executed only once if a certain condition occurs.
Usage