Spec-Zone.ru › Angular

Асинхронная реактивность с ресурсами

Все API сигналов синхронны — signal, computed, input и т. д. Однако приложениям часто приходится работать с данными, доступными асинхронно. Resource позволяет включать асинхронные данные в код приложения, основанный на сигналах, и при этом получать к ним синхронный доступ.

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

Проще всего создать Resource с помощью функции resource.

import {resource, Signal} from '@angular/core';

const userId: Signal<string> = getUserId();

const userResource = resource({
  // Define a reactive computation.
  // The params value recomputes whenever any read signals change.
  params: () => ({id: userId()}),

  // Define an async loader that retrieves data.
  // The resource calls this function every time the `params` value changes.
  loader: ({params}) => fetchUser(params),
});

// Create a computed signal based on the result of the resource's loader function.
const firstName = computed(() => {
  if (userResource.hasValue()) {
    // `hasValue` serves 2 purposes:
    // - It acts as type guard to strip `undefined` from the type
    // - It protects against reading a throwing `value` when the resource is in error state
    return userResource.value().firstName;
  }

  // fallback in case the resource value is `undefined` or if the resource is in error state
  return undefined;
});

Функция resource принимает объект ResourceOptions с двумя основными свойствами: params и loader.

Свойство params задаёт реактивное вычисление, которое возвращает значение параметра. Когда сигналы, прочитанные в этом вычислении, меняются, ресурс возвращает новое значение параметра, подобно computed.

Свойство loader задаёт ResourceLoader — асинхронную функцию, которая получает некоторое состояние. Ресурс вызывает загрузчик каждый раз, когда вычисление params возвращает новое значение, и передаёт это значение загрузчику. Подробнее см. ниже в разделе Загрузчики ресурсов.

У Resource есть сигнал value, содержащий результаты работы загрузчика.

Загрузчики ресурсов

При создании ресурса необходимо указать ResourceLoader. Этот загрузчик представляет собой асинхронную функцию, которая принимает один параметр — объект ResourceLoaderParams — и возвращает значение.

Объект ResourceLoaderParams содержит три свойства: params, previous и abortSignal.

Свойство Описание
params Значение вычисления params ресурса.
previous Объект со свойством status, содержащим предыдущий ResourceStatus.
abortSignal AbortSignal. Подробнее см. ниже в разделе Отмена запросов.

Если вычисление params возвращает undefined, функция загрузчика не запускается, а статус ресурса становится 'idle'.

Отмена запросов

Ресурс прерывает выполняющуюся операцию загрузки, если вычисление params меняется во время загрузки ресурса.

Чтобы обрабатывать отменённые запросы, используйте abortSignal из ResourceLoaderParams. Например, встроенная функция fetch принимает AbortSignal:

const userId: Signal<string> = getUserId();

const userResource = resource({
  params: () => ({id: userId()}),
  loader: ({params, abortSignal}): Promise<User> => {
    // fetch cancels any outstanding HTTP requests when the given `AbortSignal`
    // indicates that the request has been aborted.
    return fetch(`users/${params.id}`, {signal: abortSignal});
  },
});

Подробнее об отмене запросов с помощью AbortSignal см. в документации AbortSignal на MDN.

Повторная загрузка

Вы можете программно запустить loader ресурса, вызвав метод reload.

const userId: Signal<string> = getUserId();

const userResource = resource({
  params: () => ({id: userId()}),
  loader: ({params}) => fetchUser(params),
});

// ...

userResource.reload();

Статус ресурса

Объект ресурса содержит несколько свойств-сигналов для чтения статуса асинхронного загрузчика.

Свойство Описание
value Последнее значение ресурса или undefined, если значение ещё не получено.
hasValue Имеет ли ресурс значение.
error Последняя ошибка, возникшая при работе загрузчика ресурса, или undefined, если ошибок не было.
isLoading Выполняется ли в данный момент загрузчик ресурса.
status Конкретный ResourceStatus ресурса, описанный ниже.

Сигнал status предоставляет конкретный ResourceStatus, описывающий состояние ресурса с помощью строковой константы.

Статус value() Описание
'idle' undefined У ресурса нет допустимого запроса, и загрузчик ещё не запускался.
'error' undefined При работе загрузчика произошла ошибка.
'loading' undefined Загрузчик выполняется в результате изменения значения params.
'reloading' Предыдущее значение Загрузчик выполняется в результате вызова метода reload ресурса.
'resolved' Полученное значение Загрузчик завершил работу.
'local' Локально заданное значение Значение ресурса задано локально с помощью .set() или .update()

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

Реактивное получение данных с помощью httpResource

httpResource — это обёртка над HttpClient, которая предоставляет статус запроса и ответ в виде сигналов. Она выполняет HTTP-запросы через стек HTTP Angular, включая интерсепторы.

Композиция ресурсов с помощью снимков

ResourceSnapshot — это структурированное представление текущего состояния ресурса. У каждого ресурса есть свойство snapshot, предоставляющее сигнал его текущего состояния.

const userId: Signal<string> = getUserId();

const userResource = resource({
  params: () => ({id: userId()}),
  loader: ({params}) => fetchUser(params),
});

const userSnapshot = userResource.snapshot;

Каждый снимок содержит status и либо value, либо error.

Композиция ресурсов с помощью снимков

Вы можете создавать новые ресурсы на основе снимков с помощью resourceFromSnapshots. Это позволяет комбинировать их с API сигналов, например computed и linkedSignal, чтобы преобразовывать поведение ресурсов.

import {linkedSignal, resourceFromSnapshots, Resource, ResourceSnapshot} from '@angular/core';

function withPreviousValue<T>(input: Resource<T>): Resource<T> {
  const derived = linkedSignal<ResourceSnapshot<T>, ResourceSnapshot<T>>({
    source: input.snapshot,
    computation: (snap, previous) => {
      if (snap.status === 'loading' && previous && previous.value.status !== 'error') {
        // When the input resource enters loading state, we keep the value
        // from its previous state, if any.
        return {status: 'loading' as const, value: previous.value.value};
      }

      // Otherwise we simply forward the state of the input resource.
      return snap;
    },
  });

  return resourceFromSnapshots(derived);
}

@Component({
  /*... */
})
export class AwesomeProfile {
  userId = input.required<number>();
  user = withPreviousValue(httpResource(() => `/user/${this.userId()}`));
  // When userId changes, user.value() keeps the old user data until the new one loads
}

Super-powered by Google ©2010–2025.
Code licensed under an MIT-style License. Documentation licensed under CC BY 4.0.
https://angular.dev/guide/signals/resource

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API