Зачем использовать резольвер с Angular

Мне нравится идея resolver s.

Вы можете сказать, что:
- для данного маршрута вы ожидаете, что некоторые данные будут загружены сначала
- вы можете просто иметь действительно простой компонент без видимых (как получение данных из this.route.snapshot.data)

Так что резольверы имеют большой смысл.

НО:
 - Вы не изменяете URL-адрес и не показываете запрашиваемый компонент до получения фактического ответа. Таким образом, вы не можете (просто) показать пользователю, что что-то происходит путем рендеринга вашего компонента и показывать столько, сколько вы можете (как это было рекомендовано, для приложения оболочки с PWA). Это означает, что при наличии плохой связи ваш пользователь может просто ждать без визуального указания на то, что происходит в течение длительного времени
 - Если вы используете распознаватель на маршруте с параметром, возьмите пример users/1, он будет работать нормально в первый раз. Но если вы перейдете к users/2, ничего не произойдет, если вы не начнете использовать другое наблюдаемое: this.route.data.subscribe()

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

Я что-то упустил? Есть ли способ использовать их с этими реальными ограничениями?

Ответ 1

Resolver: выполняется еще до того, как пользователь перенаправлен на новую страницу.

Всякий раз, когда вам нужно получить данные до инициализации компонента, правильный способ сделать это - использовать распознаватель. Resolver действует синхронно, т.е. resolver будет ожидать завершения асинхронного вызова и только после обработки асинхронного вызова перенаправит его на соответствующий URL-адрес. Таким образом, инициализация компонента будет ожидать завершения обратного вызова. Таким образом, если вы хотите что-то сделать (вызов службы), даже до инициализации компонента, вы попали в нужное место.

Пример сценария: я работал над проектом, в котором пользователь передал бы имя файла для загрузки в URL. Основываясь на переданном имени, мы выполняем асинхронный вызов в ngOnInit и получаем файл. Но проблема в том, что если пользователь передает неправильное имя в URL, наш сервис попытается получить файл, который не существует на сервере. У нас есть 2 варианта в таком сценарии:

Вариант 1: получить список допустимых имен файлов в ngOnInit, а затем вызвать фактическую службу для извлечения файла (если имя файла допустимо). Оба эти вызова должны быть синхронными.

Вариант 2. Извлечение списка допустимых имен файлов в распознавателе, проверка правильности имени файла в URL-адресе и получение данных файла.

Вариант 2 - лучший выбор, так как распознаватель обрабатывает синхронность вызовов.

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

Ответ 2

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

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

Например, если вы используете что-то вроде Material или Cdk, вы можете отправить диалоговое окно "Загрузка", чтобы отобразить индикатор прогресса в начале разрешения, а затем закрыть диалоговое окно после завершения разрешения. Вот так:

constructor(route: ActivatedRouteSnapshot, myService: MyService, dialog: MatDialog) {}

resolve() {
    const dialogRef = this.dialog.open(ProgressComponent);
    return this.myService.getMyImportantData().pipe(
        tap(data => this.myService.storeData(data)),
        tap(() => dialogRef.close()),
        map(() => true),
        catchError(err => of(false))
    );
}

Если вы используете ngrx, вы можете сделать что-то подобное, отправляя действия в процессе разрешения.

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

Ответ 3

Вот почему я бы использовал резольвер:

  • Одиночная ответственность, моему компоненту нужны некоторые данные, в некоторых случаях эти данные предоставляются кэшем или состоянием, при пропадании мне нужно сначала их получить и передать напрямую, не меняя мой компонент. Пример: на странице результатов поиска со списком myapp.com/lists перейдите к одному элементу списка myapp.com/lists/1, где показаны подробности этого элемента, не нужно извлекать данные, уже выполненные поиском. Затем предположим, что вы переходите непосредственно к myapp.com/lists/1 вам нужно получить, и затем переходите к компоненту.
  • Изолируйте ваш компонент от логики маршрутизатора.
  • Мой компонент не должен управлять состоянием загрузки запроса на выборку, он только отвечает за отображение данных

Рассматривайте распознаватель как промежуточное ПО между вашим приложением и вашим компонентом, вы можете управлять представлением загрузки в родительском компоненте, в который входит <router-outlet>.

Ответ 4

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