Игривый подход к изучению новых хуков жизненного цикла Angular, предназначенных только для браузера.

Поскольку команда Angular продолжает работать над улучшениями инфраструктуры, такими как детальная реактивность с сигналами и частичная гидратация с помощью рендеринга на стороне сервера (SSR), они представили два новых хука. Эти хуки будут особенно полезны, когда нам нужно обновить DOM с нашим состоянием, но только при запуске в браузере.

Из Угловой документации:

Иногда необходимо использовать API-интерфейсы только для браузера, чтобы вручную читать или писать DOM. Это может быть сложно сделать с описанными выше событиями жизненного цикла, поскольку они также будут выполняться во время рендеринга на стороне сервера и предварительного рендеринга. Для этой цели в Angular предусмотрены afterRender и afterNextRender. Эти функции можно использовать безоговорочно, но они будут влиять только на браузер. Обе функции принимают обратный вызов, который будет запущен после завершения следующего цикла обнаружения изменений (включая любые вложенные циклы).

Итак, это означает, что теперь у нас есть два метода, которые только выполняются в браузере, что делает наши обновления DOM безопасными даже при использовании SSR или предварительной отрисовки.

afterNextRender

Выполните однократную инициализацию или наблюдайте за одним конкретным изменением в DOM.

Это событие запускается один раз после следующего цикла обнаружения изменений, инициируемого Angular. Таким образом, это событие идеально подходит для любого кода инициализации, который вам нужен в вашем приложении, например, для любых сторонних библиотек или API-интерфейсов только для браузера (например, для инициализации API ResizeObserver).

послеRender

Синхронизируйте состояние с DOM.

При каждом цикле обнаружения изменений это событие будет инициироваться и выполняться. Это идеально подходит для обновления DOM каждый раз, когда Angular обнаруживает изменения. Вы можете использовать его для дополнительной записи (или чтения) DOM на основе обновления приложения.

Догони синюю точку!

Хорошо, мы все знаем, что читать документацию о новой функции — это не то же самое, что использовать ее в приложении. Вы будете следить за мной, пока я буду демонстрировать небольшое приложение (или лучше сказать игру?), которое я создал с помощью Сигналы и afterNextRender и afterRender.

Вы можете попробовать игру здесь: https://after-render.netlify.app/ и просмотреть код на GitHub https://github.com/eduardoRoth/after-render

Цель этой игры — перемещать красную точку по доске, пока не коснетесь синей точки, которая (сюрприз!) переместится в другое положение.

Мы используем HostListener для отслеживания события keydown на странице, а затем перемещаем красную точку. Если обновленные координаты красной точки совпадают с координатами синей точки, мы также обновляем ее положение.

@HostListener('document:keydown', ['$event']) onKeydown(
    event: KeyboardEvent,
  ) {
    switch (event.key) {
      case 'ArrowLeft': // left
        this.moveHorizontal(-PIXELS_MOVEMENT);
        break;
      case 'ArrowUp': // up
        this.moveVertical(-PIXELS_MOVEMENT);
        break;
      case 'ArrowRight': // right
        this.moveHorizontal(PIXELS_MOVEMENT);
        break;
      case 'ArrowDown': // down
        this.moveVertical(PIXELS_MOVEMENT);
        break;
    }
  }

Мы используем WritableSignal<number> для хранения оценки и обновления DOM каждый раз, когда ее значение обновляется. Положение красной и синей точек также сохраняется в файле WritableSignal<[number, number]>, который представляет координаты x и y доски.

position = signal<[number, number]>([0, 0]);
positionPointToTouch = signal<[number, number]>([
  CONTAINER_SIZE - POINT_SIZE,
  CONTAINER_SIZE - POINT_SIZE,
]);
score = signal<number>(0);

У нас есть два метода обновления точек и один — проверить, коснулась ли красная точка синей точки:

private movePoint(axis: number, amount: number, maxAxisPosition: number) {...}
private movePointToTouch() {...}
private hasTouchedPoint() {...}

movePoint обрабатывает обновление сигнала положения красной точки новыми координатами.

movePointToTouch обрабатывает обновление сигнала положения синей точки новыми координатами.

hasTouchedPoint — это метод проверки совпадения координат положения красной и синей точки, а затем вызывает метод для перемещения синей точки.

Итак, логика у нас настроена, но как мы можем обновить DOM? Используя afterRender!

По мере обновления сигналов они запускают цикл обнаружения изменений в Angular, который затем запускает событие afterRender. Мы можем извлечь из этого пользу, вызывая методы, которые рисуют красную и синюю точку на доске каждый раз, когда обрабатывается изменение:

constructor() {
  afterRender(() => {
    this.drawPoint();
    this.drawPointToTouch();
  });
 ...
}
private drawPoint() {
  const [x, y] = this.position();
  this.point.nativeElement.setAttribute(
    'style',
    `transform: translateY(${y}px) translateX(${x}px)`,
  );
}

private drawPointToTouch() {
  const [x, y] = this.positionPointToTouch();
  this.pointToTouch.nativeElement.setAttribute(
    'style',
    `transform: translateY(${y}px) translateX(${x}px)`,
  );
}

Мы используем afterNextRender для запуска метода init board, который просто обновляет DOM. Это идеальное место, если мы хотим однажды изменить наш DOM.

constructor() {
 ...
  afterNextRender(() => {
    this.drawInitBoard();
  });
}
private drawInitBoard() {
  this.playingArea.nativeElement.setAttribute(
    'style',
    `border:3px solid #dedede;`,
  );
  const instructions = document.createElement('div');
  instructions.innerHTML = `<p style="font-weight: bolder; font-size:1.2rem;">Using your arrow keys, move the red dot to catch the blue one</p>`;
  this.playingArea.nativeElement.parentNode.append(instructions);
}

Как вы можете видеть, оценка обновляется с помощью функции обнаружения угловых изменений посредством детальной реактивности сигналов, но положение точек обрабатывается событием afterRender.

ExpressionChangedAfterItHasBeenCheckedError что?

Если вы попытаетесь обновить любую переменную в событии afterRender, вы получите эту ошибку; поэтому это событие следует использовать только для дополнительных операций чтения и записи в DOM, а не для обновления вашего состояния или чего-либо еще.

Обновления DOM стали проще

Итак, используя afterRender, мы гарантируем, что красные и синие точки обновляются в DOM каждый раз, когда обновляется их значение позиции.

Наши приложения открывают множество возможностей, которые откроют afterRender и afterNextRender.

Помните, что afterRender и afterNextRender находятся на стадии предварительного просмотра и их API могут быть изменены.

О HeroDevs

HeroDevs — студия разработки программного обеспечения и консалтинга, специализирующаяся на интерфейсной разработке. Наша команда является автором или соавтором таких проектов, как Angular CLI, Angular Universal, Scully, XLTS — расширенная долгосрочная поддержка AngularJS, Vue2, Protractor и многих других. Мы работаем с быстрорастущими стартапами и некоторыми крупнейшими компаниями мира, такими как Google, GE, Capital One, Experian, T-Mobile, Corteva и другими. Узнайте больше о нас на сайте herodevs.com.