带有 RxMethod 的 Angular ngrx-signal 不使用初始值

问题描述 投票:0回答:1

我想在下面的 Angular 17.2 组件的 ts 文件中基于信号执行一些逻辑。我想使用 @ngrx/signals 包和 rxMethod 来处理我的获取请求。然而这似乎是一个问题,因为当代码执行时,信号的值是初始值。

我可以做什么来解决这个问题?在我看来,我可以使用 rxjs-interop 的 toObservable 将组件中的信号转换回可观察的,然后使用 toSignal 将响应转换回信号,以便获得模板中信号的好处。这感觉就像这里发生了太多转换......

或者也许我可以在组件中使用 RxMethod,但在商店中拥有与信号相关的代码似乎更好......

不确定如何处理这个问题,我可以使用一些建议

店铺:

import { inject } from "@angular/core";
import { pipe, switchMap } from "rxjs";
import { patchState, signalStore, withMethods, withState } from "@ngrx/signals";
import { rxMethod } from "@ngrx/signals/rxjs-interop";
import { tapResponse } from "@ngrx/operators";
import { Article } from "../models/article.model";
import { ArticlesService } from "../services/articles.service";
import { ArticleListConfig } from "../models/article-list-config.model";

type ArticlesState = {
  articles: Article[];
  article: Article;
  slug: string;
  config: ArticleListConfig;
};

const initialState: ArticlesState = {
  articles: [],
  article: {
    slug: "",
    title: "",
    description: "",
    body: "",
    tagList: [],
    createdAt: "",
    updatedAt: "",
    favorited: false,
    favoritesCount: 0,
    author: {
      username: "",
      bio: "",
      image: "",
      following: false,
    },
  },
  slug: "",
  config: {
    type: "",
    filters: {
      tags: [],
    },
  },
};

export const ArticlesStore = signalStore(
  withState(initialState),
  withMethods((store, articlesService = inject(ArticlesService)) => ({
    getBySlug: rxMethod<string>(
      pipe(
        switchMap((slug) => {
          return articlesService.get(slug).pipe(
            tapResponse({
              next: (article) => patchState(store, { article }),
              error: console.error,
            })
          );
        })
      )
    ),
  }))
);

服务:

import { Injectable, inject } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs";
import { map } from "rxjs/operators";
import { Article } from "../models/article.model";

@Injectable({ providedIn: "root" })
export class ArticlesService {
  http = inject(HttpClient);

  constructor() {}

  get(slug: string): Observable<Article> {
    return this.http
      .get<{ article: Article }>(`/articles/${slug}`)
      .pipe(map((data) => data.article));
  }

}

成分:

import { CommonModule } from "@angular/common";
import { ChangeDetectionStrategy, Component, OnInit, effect, inject } from "@angular/core";
import { ActivatedRoute } from "@angular/router";
import { ArticlesStore } from "src/app/core/stores/article.store";

@Component({
  selector: "app-editor-page",
  templateUrl: "./editor.component.html",
  imports: [ CommonModule],
  standalone: true,
  providers: [ArticlesStore],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class EditorComponent implements OnInit {
  readonly articlesStore = inject(ArticlesStore);
  slug: string = "";

  constructor(
    private readonly route: ActivatedRoute,
  ) {
    effect(() => {
      console.log(this.articlesStore.article()); // This outputs twice, first the initial value then the value based on the response
    });
  }

  ngOnInit() {
    this.slug = this.route.snapshot.params["slug"];
    this.articlesStore.slug = this.route.snapshot.params["slug"];
    this.articlesStore.getBySlug(this.articlesStore.slug);
    console.log(this.articlesStore.article()); // This outputs the initial value once
  }
}
angular signals ngrx
1个回答
0
投票

如果您想在从请求中获得第一个结果时执行一些逻辑,请考虑使用

effect
,这样您就可以看着
article
填充数据,然后因为不再需要而销毁效果

export class EditorComponent implements OnInit {
...
  #initialArticleHandle = effect(() => {
    const article = this.articlesStore.article();
    if(article === null) return;
    if(article.author.username === this.testUserName) {  
      // do your stuff
    }
    else {
      this.router.navigateByUrl('/');
    }
    #initialArticleHandle.destroy(); // destroy effect not to listen article changes further, we've done everything we wanted
  });
© www.soinside.com 2019 - 2024. All rights reserved.