monkey
monkey

Reputation: 1651

How / whether to replace a getter with a parameter by a computed signal

Is there a comparable signals based approach to something like this:

/** PROPS */

selectedOption = signal<string | null>(null);

getSelectedState(option: string): boolean | undefined {
  if (this.selectedOption() === null) {
    return undefined;
  }
  return option === this.selectedOption();
}


@for (option of list(); track option) {
  <monkey-chip
    [variant]="'frequency-sel'"
    [text]="option"
    [selected]="getSelectedState(option)"
    (click)="onSelect(option)"
  />
}

What I'd like to achieve is a computed value to replace getSelectedState(option), but I don't know how this would work...

Can we make this fully reactive, to the extent that zone.js could be removed and it would still work?

I played around with computed, but as I understand it computed doesn't accept any arguments, so that isn't really any use.

Upvotes: 1

Views: 40

Answers (2)

Naren Murali
Naren Murali

Reputation: 57986

Problem:

The problem with this providing the computed in a getter function is that a new instance of computed is created on every change detection cycle, which is wrong and could lead to a memory leak (If the change detection is fired enough times on the same component)

There should be only one instance of a computed created for a specific derived state and it should be recreated.


Reason:

The computed will create a derived state based on the signals inside it, but it does not accept dynamic properties.

Although this can be classified as derived state, it accepts dynamic input, which computed cannot handle.


Solution:

If you are able to modify the contents of monkey-child, then this solution is best:

Parent:
@for (option of list(); track option) {
  <monkey-chip
    [variant]="'frequency-sel'"
    [text]="option"
    [selectedOption]="selectedOption()"
    (click)="onSelect(option)"
  />
}
Child:
@Component({ selector: 'monkey-child', ... })
export class MonkeyChilComponent {
  selectedOption = input(null);
  selected = computed(()=>{
    if (this.selectedOption() === null) {
      return undefined;
    }
    return option === this.selectedOption();
  });
  ...

You should directly use the signal to perform the comparison on HTML side, because the signal when changed, will perform the check on change detection.

Also enable changeDetection: ChangeDetectionStrategy.OnPush for best performance.

@for (option of list(); track option) {
  <monkey-chip
    [variant]="'frequency-sel'"
    [text]="option"
    [selected]="getSelectedState(option)"
    (click)="option === this.selectedOption()"
  />
}

Upvotes: 0

YunHai
YunHai

Reputation: 1

Maybe you can achieve a function that accept arguments and return a computed signal,like this:

/** PROPS */

selectedOption = signal<string | null>(null);

getSelectedState(option: string): boolean | undefined {
  return computed(()=>{
    if (this.selectedOption() === null) {
      return undefined;
    }
    return option === this.selectedOption();})
}


@for (option of list(); track option) {
  <monkey-chip
    [variant]="'frequency-sel'"
    [text]="option"
    [selected]="getSelectedState(option)"
    (click)="onSelect(option)"
  />
}

Upvotes: 0

Related Questions