Действие диспетчеризации ngrx для компонента (связанного с маршрутом) init

угловой 5+, ngrx 4+

То, что я пытаюсь сделать, это вызвать ARTICLES_LIST_REQUEST, когда инициализируется ArticlesListComponent, связанный с path /articles.

Есть множество способов сделать это, например, используя dispatch внутри ngOnInit, используя dispatch на охраннике, но вместо этого я хочу использовать @ngrx/router-store, слушать ROUTER_NAVIGATION и сопоставлять его с ARTICLES_LIST_REQUEST (на самом деле ARTICLES_LIST_PARAMS_SET, чтобы сохранить текущий маршрут params в магазин, но это не беда), сейчас с этим пара проблем.

Поскольку эффекты, даже те, которые зарегистрированы с помощью forFeature, работают глобально, если бы я настроил этот эффект на прослушивание ROUTER_NAVIGATION внутри нескольких модулей (статьи, люди, бренды и т. д.), он будет запускаться несколько раз, вызывая все действия одновременно, поэтому мне нужен способ отфильтровать его только для интересующего меня маршрута ... но как? Поскольку в угловом маршрутизаторе нет именованных маршрутов, а действие навигации возвращает снимок всего дерева, невозможно узнать, что конкретный маршрут только что активирован. Что я делаю в данный момент, так это проверяю и фильтрую по URL-адресу, например, начинается ли он с /articles и не является ли следующий символ / (чтобы отфильтровать /articles/<id>. Но мне это очень не нравится, на самом деле не чувствую вроде бы благополучно покроет все случаи.

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

Должен ли я вообще не использовать для этого router-store?


person fxck    schedule 23.09.2017    source источник


Ответы (1)


Вот что у меня получилось:

1) Добавьте уникальный name в data определений маршрутов.

export const ROUTES: Routes = [
  {
    path: '/articles',
    component: ArticlesListPage,
    data: {
      name: 'articles-list'
    }
  }
];

2) создайте собственный сериализатор для router-store, который извлекает только params, queryParams и name (из data.name) для каждого дочернего элемента в дереве

function createSerializedTree(node: ActivatedRouteSnapshot) {
  const tree = {
    queryParams: node.queryParams,
    params: node.params,
    name: node.data.name,
    children: node.children.map(createSerializedTree),
    firstChild: undefined
  };

  tree.firstChild = tree.children[0];

  return tree;
}

3) создайте функцию для let, которая фильтрует и сопоставляет с первым маршрутом с именем, соответствующим указанному вами.

const _checkIsNodeHasName = (name: string, node: SerializedRouterNode) => {
  if (node.name === name) {
    return node;
  } else if (node.firstChild) {
    return _checkIsNodeHasName(name, node.firstChild);
  } else {
    return undefined;
  }
}

export const filterAndMapRoute = (name: string) => {
  return (navigationAction$: Observable<RouterNavigationAction<RouterStateUrl>>) => {
    return navigationAction$
      .map(action => action.payload.routerState)
      .filter((state) => !!_checkIsNodeHasName(name, state.root))
      .map((state) => _checkIsNodeHasName(name, state.root));
  };
};

Теперь я могу сделать это

@Injectable()
export class ArticlesEffects {
  @Effect()
  private _onRouteChange$ = this._action$
    .ofType(ROUTER_NAVIGATION)
    .let(filterAndMapRoute('posts-list'))
    .map(/* ... */) // map to whatever action I need
}

Это более или менее просто доказательство концепции, на самом деле мне нужно проверить не только firstChild, но и всех детей.

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

/articles/:id/graph / /articles/:id/table, последний firstChild, не будет содержать id, поэтому необходимо найти первого дочернего элемента, который соответствует имени, и сопоставить его (и отфильтровать, если ничего не найдено).

person fxck    schedule 23.09.2017
comment
Мне нравится использование атрибута данных, приятно. Эта статья может предоставить дополнительную помощь в извлечении основного firstChild, а затем вы можете добавить к нему (mergedRoute) для построения полного дерева: medium.com/simars/ - person rmcsharry; 01.10.2019
comment
Прошло некоторое время, сейчас я использую вариант этого github.com/amcdnl/ngrx-router/blob/master/src/operator.ts#L24 - person fxck; 01.10.2019
comment
Спасибо, не знал о таких операторах, очень пригодилось! - person rmcsharry; 01.10.2019