← Назад к вопросам

Что такое detectChanges?

1.7 Middle🔥 151 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

detectChanges в Angular

detectChanges - это метод компонента в Angular, который вручную запускает проверку изменений (change detection) для компонента и его потомков.

import { Component, ChangeDetectionStrategy } from '@angular/core';

@Component({
  selector: 'app-counter',
  template: '<p>Count: {{ count }}</p><button (click)="increment()">+</button>',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class CounterComponent {
  count = 0;
  
  increment() {
    this.count++;
  }
}

По умолчанию Angular использует стратегию Default, которая проверяет изменения автоматически. Но при использовании OnPush нужно вручную запускать detectChanges.

Когда используется detectChanges

Основная причина - использование ChangeDetectionStrategy.OnPush. Эта стратегия игнорирует события и таймеры, проверяя только изменения input свойств.

import { ChangeDetectorRef } from '@angular/core';

@Component({
  selector: 'app-timer',
  template: '<p>{{ time }}</p>',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class TimerComponent implements OnInit {
  time = 0;
  
  constructor(private cdr: ChangeDetectorRef) {}
  
  ngOnInit() {
    setInterval(() => {
      this.time++;
      // Без этого вызова template не обновится!
      this.cdr.detectChanges();
    }, 1000);
  }
}

Без detectChanges template остаётся прежним, хотя значение time увеличивается.

Стратегия Default vs OnPush

// Default - проверяет изменения часто (может быть неэффективно)
@Component({
  selector: 'app-default',
  template: '<p>{{ count }}</p>'
  // changeDetection не указана, используется Default
})
export class DefaultComponent {
  count = 0;
}

// OnPush - проверяет только при изменении input
@Component({
  selector: 'app-optimized',
  template: '<p>{{ count }}</p>',
  changeDetection: ChangeDetectionStrategy.OnPush,
  inputs: ['count']
})
export class OptimizedComponent {
  @Input() count = 0;
}

OnPush более эффективна, потому что Angular не проверяет компонент при каждом событии, а только когда меняются его input свойства.

ChangeDetectorRef методы

import { ChangeDetectorRef } from '@angular/core';

@Component({...})
export class MyComponent {
  constructor(private cdr: ChangeDetectorRef) {}
  
  // detectChanges() - запусти проверку изменений для этого компонента
  updateData() {
    this.data = newValue;
    this.cdr.detectChanges();
  }
  
  // markForCheck() - отметить компонент как требующий проверки
  onDataChange() {
    this.cdr.markForCheck();
  }
  
  // detach() - отключить автоматическую проверку
  disableAutoDetection() {
    this.cdr.detach();
  }
  
  // reattach() - включить обратно
  enableAutoDetection() {
    this.cdr.reattach();
  }
}

Пример с асинхронными операциями

@Component({
  selector: 'app-async-data',
  template: '<p>{{ data | json }}</p>',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AsyncDataComponent implements OnInit {
  data: any;
  
  constructor(
    private http: HttpClient,
    private cdr: ChangeDetectorRef
  ) {}
  
  ngOnInit() {
    // Observable автоматически не запускает detectChanges
    this.http.get('/api/data').subscribe(result => {
      this.data = result;
      // Без этого template не обновится
      this.cdr.detectChanges();
    });
  }
}

Почему detectChanges нужна

  1. OnPush стратегия - Angular не проверяет автоматически
  2. Асинхронные события - setTimeout, setInterval, Promise
  3. Внешние библиотеки - события, которые Angular не знает
  4. Производительность - контролируешь когда проверять изменения

Сравнение с React

В React нет detectChanges, потому что React по-другому работает с изменениями. React использует Virtual DOM и автоматически перерендеривает при изменении state или props.

// React - автоматически обновляется
function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>+</button>
    </div>
  );
}

// Angular с OnPush - нужен detectChanges
@Component({
  selector: 'app-counter',
  template: '<p>Count: {{ count }}</p><button (click)="increment()">+</button>',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class CounterComponent {
  count = 0;
  
  constructor(private cdr: ChangeDetectorRef) {}
  
  increment() {
    this.count++;
    this.cdr.detectChanges(); // Angular нужна помощь
  }
}

Практические советы

  1. Используй OnPush - это лучшая практика для производительности
  2. Инъектируй ChangeDetectorRef - когда нужна вручную запустить проверку
  3. Избегай Default - слишком медленно на больших приложениях
  4. Тестируй detectChanges - в unit тестах вызывай detectChanges перед assertions
// Unit тест
it('should update view', () => {
  component.count = 5;
  fixture.detectChanges(); // Запусти проверку изменений
  
  const compiled = fixture.nativeElement;
  expect(compiled.textContent).toContain('5');
});

detectChanges - это инструмент для оптимизации Angular приложений, особенно важен при использовании OnPush стратегии.

Что такое detectChanges? | PrepBro