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

feat(explicitEffect): addition of defer parameter; this parameter all… #431

Merged
merged 2 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions docs/src/content/docs/utilities/Signals/explicit-effect.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,29 @@ explicitEffect(

## Cleanup

An optional second argument can be provided to `explicitEffect` that will be called when the effect is cleaned up.
An optional second argument can be provided to the `explicitEffect` function that will be called when the effect is cleaned up.

```ts
const count = signal(0);
explicitEffect([this.count], ([count], cleanup) => {
explicitEffect([count], ([count], cleanup) => {
console.log(`count updated ${count}`);
cleanup(() => console.log('cleanup'));
});
```

## Defer

In addition to the regular `effect` options, you can also pass a `defer` value as part of the third object argument of `explicitEffect`. This allows the computation not to execute immediately and only run on first deps change.

```ts
const count = signal(0);
explicitEffect(
[count],
([count]) => {
console.log(`count updated ${count}`);
},
{ defer: true },
);

// count updated 0
// count.set(1);
// cleanup
// count updated 1
count.set(1); // this set will trigger the effect function call, not the initial value
```
23 changes: 23 additions & 0 deletions libs/ngxtension/explicit-effect/src/explicit-effect.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,27 @@ describe(explicitEffect.name, () => {
});
});
});

it('should skip the first run of the effect callback', () => {
const log: string[] = [];
const count = signal(0);
const state = signal('idle');

TestBed.runInInjectionContext(() => {
explicitEffect(
[count, state],
([count, state]) => {
log.push(`count updated ${count}, ${state}`);
},
{ defer: true },
);
expect(log.length).toBe(0);
TestBed.flushEffects();
expect(log.length).toBe(0);

count.set(1);
TestBed.flushEffects();
expect(log.length).toBe(1);
});
});
});
22 changes: 19 additions & 3 deletions libs/ngxtension/explicit-effect/src/explicit-effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ type ExplicitEffectValues<T> = {
[K in keyof T]: () => T[K];
};

/**
* Extend the regular set of effect options
*/
declare interface CreateExplicitEffectOptions extends CreateEffectOptions {
/**
* Option that allows the computation not to execute immediately, but only run on first change.
*/
defer?: boolean;
}

/**
* This explicit effect function will take the dependencies and the function to run when the dependencies change.
*
Expand All @@ -34,18 +44,24 @@ type ExplicitEffectValues<T> = {
*
* @param deps - The dependencies that the effect will run on
* @param fn - The function to run when the dependencies change
* @param options - The options for the effect
* @param options - The options for the effect with the addition of defer (it allows the computation to run on first change, not immediately)
*/
export function explicitEffect<
Input extends readonly unknown[],
Params = Input,
>(
deps: readonly [...ExplicitEffectValues<Input>],
fn: (deps: Params, onCleanup: EffectCleanupRegisterFn) => void,
options?: CreateEffectOptions | undefined,
options?: CreateExplicitEffectOptions | undefined,
): EffectRef {
let defer = options && options.defer;
return effect((onCleanup) => {
const depValues = deps.map((s) => s());
untracked(() => fn(depValues as any, onCleanup));
untracked(() => {
if (!defer) {
fn(depValues as any, onCleanup);
}
defer = false;
});
}, options);
}
Loading