首页 > 解决方案 > Angular 使用 Akita 商店 ngOnInit 在首次加载时不起作用

问题描述

我的 Angular10 应用程序使用 Akita 商店时遇到问题。

当我在我的组件页面上启动/刷新我的应用程序时,我在我的组件上看到 LOADING。

但是,通过控制台,看起来商店已经加载了项目,并且我的 console.logs 在 onInit 中被触发。

当我在他们应该加载的页面上刷新应用程序时,它不会,它只会显示“正在加载”。但是,如果我单击此页面的路由器链接按钮,它将加载。

/models/post post.model.ts

export interface Post {
// fields here
}

/stores/post post.store.ts

export interface PostsState extends EntityState<Post, number> {
    posts: Post[];
    isLoaded: boolean;
}

export const getInitialState = () => {
    return {
        posts: [],
        isLoaded: false,
    };
};

@Injectable({
    providedIn: 'root'
})
@StoreConfig({name: ‘postsStore'})
export class PostsStore extends EntityStore<PostsState> {
    constructor() {
        super(getInitialState());
    }
}

/stores/user user.query.ts

@Injectable({ providedIn: 'root' })
export class PostsQuery extends QueryEntity<PostsState> {

  constructor(protected store: PostsStore) {
    super(store);
  }

  getPosts(): Observable<Post[]> {
    return this.select(state => state.posts);
  }

  getLoaded():Observable<boolean> {
    return this.select(state => state.isLoaded);
  }

  getIsLoading():Observable<boolean> {
    return this.selectLoading();
  }


}
import { ID } from '@datorama/akita';

服务/帖子posts.service.ts

@Injectable({ providedIn: 'root' })
export class PostsService {

  private API_URL = `${environment.apiUrl}`;


  constructor(private postsStore: PostsStore,
              private http: HttpClient) {}

  get() {
    return this.http.get<Post[]>(`${this.API_URL}/posts`)
     .pipe(
       tap(entities => this.postsStore.set(entities))
      );
  }

  add(post: Post) {
    this.postsStore.add(post);
  }

  update(id, post: Partial<Post>) {
    this.postsStore.update(id, post);
  }

视觉/视觉.component.ts

ngOnInit(): void {
    console.log('STARTING'); // on page initial this shows
    this.postsQuery.getIsLoading().subscribe(res => this.loading = res);
    this.postsQuery.getPosts().subscribe(res => this.posts = res);
    this.postsQuery.getLoaded().pipe(
      take(1),
      filter(res => !res),
      switchMap(() => {
        this.postsStore.setLoading(true);
        console.log(‘TEST ‘A); // on page initial this shows
        return this.postsService.get();
      })
      ).subscribe(res => {
        this.postsStore.update(state => {
          console.log(‘TEST ‘B); // on page initial this shows
          return {
            posts: res
          };
        });
        this.postsStore.setLoading(false);
        console.log(‘TEST’ C);  // on page initial this shows
      }, err => {
        console.log(err);
        this.postsStore.setLoading(false); 
        console.log(‘TEST ‘D); // This does not show
      });
  }

视觉/视觉.component.html

<div *ngIf="loading">
<p>
  LOADING
</p>
</div>   



<div *ngIf="!loading">
<div *ngFor="let post of posts>
{{post.name}}
<div>
</div>

标签: angularangular10angular-akitaakita

解决方案


最好在 stackblitz 上有这个例子来尝试一下(如果不调试就很难解决问题)。

另外,我建议尝试添加console.log订阅this.postsQuery.getIsLoading()以更好地调试它。

但是,现在我看到两个选项:

  1. 尝试添加订阅changeDetectorRef.detectChange()this.postsQuery.getIsLoading()

  2. 该问题可能与此问题有关https://github.com/datorama/akita/issues/653(参见 stackblitz 示例),其根本原因是在商店订阅中同步更新商店。

修复它的方法是延迟this.postsStore.setLoading(true);(您可以尝试将其放入setTimeout()或添加一些 rxjs 运算符)


推荐阅读