Обновить

Коллеги привет, искал себе решение как реагировать на изменения в объекте и нашел отличный сервис, который используется внутри директив таких как NgClass и NgStyle.

KeyValueDiffers позволяет создать KeyValueDiffer для сравнения изменений текущих пар ключ-значение с новыми. Если вы используете иммутабельные объекты, то можно просто обернуть все в эффект, ну а если вы наследники крутого легаси, где все объекты мутируются по ссылке, тогда проверку нужно вешать в DoCheck, чтобы реагировать на каждый тик change detection.

Накидал оба примера, чтобы поделиться с вами:

Иммутабельный с effect:


@Component({
  selector: 'app-test',
  template: ''
})
export class TestComponent {
  public state = input.required<Record<string, string | number>>();
  
  private differs = inject(KeyValueDiffers);
  private differ: KeyValueDiffer<string, string | number> | undefined;

  constructor() {
    effect(() => {
      const currentState = this.state();
      
      // создаем диффер, если он еще не создан
      if (!this.differ) {
        this.differ = this.differs.find(currentState).create();
      }

      // Эффект будет перезапускаться при изменении инпут-сигнала.
      const changes = this.differ.diff(currentState);

      // только если есть изменения
      if (changes) {
        changes.forEachAddedItem((record) => {
          console.log(`В объект добавлена запись: Ключ: ${record.key} | Значение: ${record.currentValue}`)
        });

        changes.forEachChangedItem((record) => {
          console.log(`Изменено: ${record.key} | Новое значение: ${record.currentValue}`)
        });

        changes.forEachRemovedItem((record) => {
          console.log(`Удалено: ${record.key}`)
        });
        
        // Остальные методы forEachItem и forEachPreviousItem по необходимости
      }
    })
  }
}

Легаси подход, которого, надеюсь, ни у кого нет, но на всякий случай :)

@Component({
  selector: 'app-legacy',
  template: ''
})
export class LegacyComponent implements OnInit, DoCheck {
  @Input({ required: true }) state!: Record<string, string | number>;
  
  private differs = inject(KeyValueDiffers);
  private differ: KeyValueDiffer<string, string | number> | undefined;

  ngOnInit() {
    // Создаем диффер при инициализации
    this.differ = this.differs.find(this.state).create();
  }

  // Запускается на каждый тик change detection, так как мутации по-другому не отследим.
  ngDoCheck(): void {
    const changes = this.differ?.diff(this.state);

    if (changes) {
      changes.forEachAddedItem((record) => {
        console.log(`В объект добавлена запись: Ключ: ${record.key} | Значение: ${record.currentValue}`)
      });

      changes.forEachChangedItem((record) => {
        console.log(`Значение изменилось: ${record.key}`)
      });

      changes.forEachRemovedItem((record) => {
        console.log(`Запись удалена: ${record.key}`)
      });

      // Остальные методы forEachItem и forEachPreviousItem по необходимости
    }
  }
}
Теги:
+1
Комментарии0

Публикации

Ближайшие события