代码之家  ›  专栏  ›  技术社区  ›  HansMusterWhatElse

角度-Ngrx-来自多个源和组件渲染的更新

  •  0
  • HansMusterWhatElse  · 技术社区  · 7 年前

    在我们的申请中 容器组件 如下所示:

    export class ArchiveAllComponent implements OnInit {
    
      archiveAllViewModel$: Observable<ArchiveAllViewModel>
    
      constructor(
        private store: Store<ApplicationState>,
        private votingService: VotingService
      ) { }
    
      ngOnInit() {
        // Subscribe to any changes in the category and voting entities
        this.archiveAllViewModel$ = this.store.pipe(
          select(selectCategoriesWithVoting),
          map((categories: Category[]) => mapToArchiveAllViewModel(categories))
        )
    
        // Load all categories
        this.votingService.getCategories().subscribe((categories: Category[]) => {
          this.store.dispatch(new LoadCategoryAction(categories));
        });
    
        // Load all votings
        this.votingService.getVotings().subscribe((votings: Voting[]) => {
          this.store.dispatch(new LoadVotingAction(votings));
        });
      }
    
    }
    

    一旦这个组件被呈现,两个HTTP GET请求将被执行到不同的API。

    对于每一个请求 商店

    减速器

    // Reducer function
    export function entityReducer(currentState: Entities, action: EntityActionsUnion): Entities {
        switch (action.type) {   
    
            case EntityActionTypes.LOAD_CATEGORIES:
                return merge({}, currentState, {categories : action.categories});
    
            case EntityActionTypes.LOAD_VOTINGS:
                return merge({}, currentState, {votings : action.votings});
    
            default:
                return currentState;
        }
    }
    

    export function selectCategoryEntity(state: ApplicationState) {
        return state.entities.categories;
    }
    
    export function selectVotingEntity(state: ApplicationState) {
        return state.entities.votings;
    }
    
    export const selectCategoriesWithVoting = createSelector(
        selectCategoryEntity,
        selectVotingEntity,
        (categoryEntities: Category[], votingEntities: Voting[]) => {
            if (categoryEntities && categoryEntities.length > 0 && votingEntities && votingEntities.length > 0) {
                let categories = categoryEntities.slice();
                votingEntities.forEach(voting => {
                    if (voting.categoryId) {
                        let category = categories.find(x => x.id == voting.categoryId);
                        if(!category.votings) 
                        {
                            category.votings = [];
                        }
                        category.votings.push(voting);
                    }
                });
    
                return categories;
            }
    
            return [];
        }
    );
    

    这个 archiveAllViewModel$ 然后,observable被传递给一些子组件,以便相应地呈现HTMl。

    1. 页面刷新
    2. getCategories()
    3. getVotings() +动作/减速器被触发
    4. <archiveElement>
    5. <架构元素> +正确呈现第二个子元素
    6. <架构元素>

    当我开始离开组件并通过客户端站点路由返回到同一路由时,问题就开始出现。

    <a routerLink="/someotherpage" routerLinkActive="active" mat-button>Other Page</a>
    

    返回到同一组件:

    <a routerLink="/archiveAll" routerLinkActive="active" mat-button>Archive</a>
    

    现在,与整页刷新相比,所有内容都呈现两次:

    1. 远航
    2. <架构元素>
    3. <架构元素>
    4. <架构元素>
    5. 获取类别() +动作/减速器被触发
    6. <
    7. <
    8. <架构元素>
    9. 获取votings() +动作/减速器被触发
    10. <
    11. <架构元素>
    12. <

    因此 .

    故障排除

    createSelector 现在对每个http请求执行一次,因为 categoryEntities && categoryEntities.length > 0 && votingEntities && votingEntities.length > 0 不再仅对第二个http请求有效 .

    • 解决这种问题的最佳做法是什么?
    2 回复  |  直到 7 年前
        1
  •  1
  •   timdeschryver    7 年前

    这里的问题是 this.votingService.getCategories() this.votingService.getVotings()

    ngDestroy ,但与其这么做,我建议您看看 @ngrx/effects 处理所有的副作用(例如http请求)。

        2
  •  0
  •   HansMusterWhatElse    7 年前

    我已经重构了它,现在似乎可以工作了!

    export const selectCategoriesWithVoting = createSelector(
        selectCategoryEntity,
        selectVotingEntity,
        (categoryEntities: Category[], votingEntities: Voting[]) => {
            if (categoryEntities && categoryEntities.length > 0 && votingEntities && votingEntities.length > 0) {
                let categories = categoryEntities.slice();       
                votingEntities.forEach(newVoting => {
                    if (newVoting.categoryId) {
                        let category = categories.find(x => x.id == newVoting.categoryId);
                        if(!category.votings) 
                        {
                            category.votings = [];
                        }                 
    
                        let oldVotingIndex = category.votings.findIndex(x => x.id == newVoting.id);
                        if(oldVotingIndex != -1)
                        {
                            category.votings[oldVotingIndex] = newVoting;
                        } else {
                            category.votings.push(newVoting);
                        }
                    }
                });
    
                return categories;
            }
    
            return [];
        }
    );