【问题标题】:How to use NGXS with route resolvers?如何将 NGXS 与路由解析器一起使用?
【发布时间】:2019-12-12 06:39:32
【问题描述】:

假设我有一个管理文章的 CRUD 应用程序。 结合路由参数使用NGXS的正确方法是什么?

当我打开应用程序时,我位于/。点击一个按钮将我带到/articles

  • 现在会发生什么?我是否需要一个路由解析器来分派 NGXS 操作来加载文章,或者文章的容器组件是否负责?
  • 当文章列表已加载(通过解析器或容器本身)时,我想单击特定文章,例如将我带到/articles/1。再说一遍:我需要一个路由解析器吗?

如果我需要路由解析器:如何在加载状态时在特定组件中显示加载微调器(例如,在文章列表中显示微调器)?唯一可能的解决方案是从解析器返回Observable<Observable>

如果不是:如果我直接前往/articles/1,谁会为我的状态正确发送必要的操作(在这种情况下,文章本身还没有加载,那么应该如何加载一篇特定的文章)?

我找不到有关此主题的任何资源。我发现的所有示例应用程序都不介意当前的路线,这会导致非常糟糕的用户体验 imo。

【问题讨论】:

    标签: angular ngxs


    【解决方案1】:

    如何将 NGXS 与路由解析器一起使用?

    非常简单 :D store.dispatch 返回一个 observable,它将在所有异步工作完成后生成一个事件并完成,因此您可以轻松地在解析器中调度操作。

    假设您有一个名为 GetArticles 的操作:

    export class GetArticles {
      public static readonly type = '[Articles] Get articles';
    }
    

    您可能希望有一个存储所有文章的状态,以及一个响应 GetArticles 的操作处理程序:

    @State({
      name: 'articles',
      defaults: []
    })
    export class ArticlesState {
      constructor(private articlesService: ArticlesService) {}
    
      @Action(GetArticles)
      public getArticles(ctx: StateContext<Article[]>) {
        return this.articlesService.getArticles().pipe(
          tap(articles => {
            ctx.setState(articles);
          })
        );
      }
    }
    

    所以你要做的是创建一个解析器,在那里调度一个动作并将流映射到文章数组,就像这样:

    @Injectable()
    export class ArticlesResolver implements Resolve<Article[]> {
      constructor(private store: Store) {}
    
      public resolve() {
        return this.store.dispatch(new GetArticles()).pipe(
          map(() => this.store.selectSnapshot(ArticlesState))
        );
      }
    }
    

    就是这样,您的ArticlesComponent 已经可以通过ActivatedRoute.prototype.snapshot.data.articles 访问预加载的文章(假设您已将解析器与resolve: { articles: ArticlesResolver } 之类的组件链接)。


    考虑到您关于路由到特定文章(如 /articles/1)的问题,如果您已经预加载了文章 - 您不能直接从 articles 数组中获取必要的文章吗?你可以创建一个选择器来搜索id的文章:

    export class ArticlesState {
      public static getArticleById(id: string) {
        return createSelector(
          [ArticlesState],
          (articles: Article[]) => articles.find(article => article.id === id)
        );
      }
    }
    

    所以你在ArticleComponent 中要做的就是通过使用id 调用这个选择器工厂从商店中选择一个快照:

    export class ArticleComponent {
      public article: Article = this.store.selectSnapshot(
        ArticlesState.getArticleById(this.route.snapshot.params.id)
      );
    
      constructor(private route: ActivatedRoute, private store: Store) {}
    }
    

    【讨论】:

    • 多么出色的答案! +1
    猜你喜欢
    • 2019-04-12
    • 2017-01-03
    • 2016-09-15
    • 2017-09-20
    • 2018-10-10
    • 2018-07-28
    • 2021-09-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多