ngrx 对组件(与路由关联)init 的调度操作
ngrx dispatching action on component (associated with a route) init
angular 5+, ngrx 4+
我想做的是在初始化 ArticlesListComponent
时触发 ARTICLES_LIST_REQUEST
,与 path
/articles
关联。
有很多方法可以做到这一点,例如在 ngOnInit
中使用 dispatch
,在守卫上使用 dispatch
,但我想做的是使用 @ngrx/router-store
, listen to ROUTER_NAVIGATION
and map it to ARTICLES_LIST_REQUEST
(actually ARTICLES_LIST_PARAMS_SET
, to save current route params to the store, but it don't matter), 现在有一对的问题。
因为效果,即使是那些在 forFeature
注册的效果,在全球范围内都是 运行ning,如果我要设置这个效果来监听 ROUTER_NAVIGATION
在多个模块(文章,人物,品牌等),它会 运行 多次,一次触发所有操作,所以我需要一种方法来仅针对我感兴趣的路线过滤它..但是如何?由于 angular 路由器和导航操作中没有命名路由 returns 整个树的快照,因此无法知道刚刚激活的特定路由。我现在正在做的是通过 url 检查和过滤,例如它是否以 /articles
开头以及下一个字符是否不是 /
(过滤掉 /articles/<id>
。但我真的不喜欢它,我真的觉得它不能安全地涵盖所有情况。
曾经有一种方法可以在组件内暂停/启动/取消订阅/订阅效果,我认为这不再可能了,但它会将责任移回组件,这不会比从组件/守卫调度动作要好得多。
我不应该为此使用 router-store
吗?
这是我最终得到的结果:
1) 添加唯一的 name
到路由定义的 data
export const ROUTES: Routes = [
{
path: '/articles',
component: ArticlesListPage,
data: {
name: 'articles-list'
}
}
];
2) 为 router-store
创建自定义 serializer,仅提取 params
、queryParams
和 name
(来自 data.name
)对于树
中的每个 child
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,还需要检查所有 children。
我首先只使用了树的最后一个 firstChild
,但在某些情况下这是行不通的,例如,如果您想从这些路线中保存 id
[=29] =]
/articles/:id/graph
/ /articles/:id/table
,最后一个 firstChild
,不会包含 id
,因此需要找到匹配的第一个 child名称并映射到该名称(如果找到 none 则进行过滤)。
angular 5+, ngrx 4+
我想做的是在初始化 ArticlesListComponent
时触发 ARTICLES_LIST_REQUEST
,与 path
/articles
关联。
有很多方法可以做到这一点,例如在 ngOnInit
中使用 dispatch
,在守卫上使用 dispatch
,但我想做的是使用 @ngrx/router-store
, listen to ROUTER_NAVIGATION
and map it to ARTICLES_LIST_REQUEST
(actually ARTICLES_LIST_PARAMS_SET
, to save current route params to the store, but it don't matter), 现在有一对的问题。
因为效果,即使是那些在 forFeature
注册的效果,在全球范围内都是 运行ning,如果我要设置这个效果来监听 ROUTER_NAVIGATION
在多个模块(文章,人物,品牌等),它会 运行 多次,一次触发所有操作,所以我需要一种方法来仅针对我感兴趣的路线过滤它..但是如何?由于 angular 路由器和导航操作中没有命名路由 returns 整个树的快照,因此无法知道刚刚激活的特定路由。我现在正在做的是通过 url 检查和过滤,例如它是否以 /articles
开头以及下一个字符是否不是 /
(过滤掉 /articles/<id>
。但我真的不喜欢它,我真的觉得它不能安全地涵盖所有情况。
曾经有一种方法可以在组件内暂停/启动/取消订阅/订阅效果,我认为这不再可能了,但它会将责任移回组件,这不会比从组件/守卫调度动作要好得多。
我不应该为此使用 router-store
吗?
这是我最终得到的结果:
1) 添加唯一的 name
到路由定义的 data
export const ROUTES: Routes = [
{
path: '/articles',
component: ArticlesListPage,
data: {
name: 'articles-list'
}
}
];
2) 为 router-store
创建自定义 serializer,仅提取 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,还需要检查所有 children。
我首先只使用了树的最后一个 firstChild
,但在某些情况下这是行不通的,例如,如果您想从这些路线中保存 id
[=29] =]
/articles/:id/graph
/ /articles/:id/table
,最后一个 firstChild
,不会包含 id
,因此需要找到匹配的第一个 child名称并映射到该名称(如果找到 none 则进行过滤)。