Reproducing child components is not used when using the OnPush strategy

@Component({
    selector: "parent",
    template: `<child [userId]="(userId$ | async)"></child>`,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class ParentCmp implements OnInit {
    userId$: BehaviorSubject<string> = new BehaviorSubject<string>(null);

    constructor(private activatedRoute: ActivatedRoute) { }
    ngOnInit() {
        this.activatedRoute.queryParams.subscribe(query => {
            //notify child with BehaviorSubject
            this.userId$.next(query["userid"])
        }
    }
}

@Component({
    selector: "child",
    template: `<div *ngIf="(userState$ | async) && userId">
                    {{(userState$ | async).user.id)}}
               </div>`,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildCmp implements OnChanges {
    @Input() userId: string;
    private userState$: Observable<User>;

    constructor(private store: Store<store.AppState>) { }
    ngOnChanges(changes: SimpleChanges) { 
        //when it gets userId it starts to track fit user in ngrx store
        this.userState$ = this.store
                .select(state => state.user-list)                 
                .map(userList => userList[this.userId])
                .filter(user => !!user);
    }
}

      

The child cmp gets the userId from the parent and the required user is contained in the ngrx store (userList), but the child is not redrawn. It works great when the DefaultDetectionStrategy is for the default child. What could be wrong here? Angular v2.4

+3


source to share


1 answer


If you change the model in ngOnChanges()

, you need to explicitly call change detection

export class ChildCmp implements OnChanges {
    @Input() userId: string;
    private userState$: Observable<User>;

    constructor(
      private store: Store<store.AppState>,
      private cdRef:ChangeDetectorRef
    ) { }
    ngOnChanges(changes: SimpleChanges) { 
        //when it gets userId it starts to track fit user in ngrx store
        this.userState$ = this.store
                .select(state => state.user-list)                 
                .map(userList => userList[this.userId])
                .filter(user => !!user);
        this.cdRef.detectChanges();
    }
}

      



or it might be better to make it userStates$

Observable and keep the same instance instead of creating a new one every time it is called ngOnChanges

:

userId$: Subject<User> = new Subject<User>();

ngOnChanges(changes: SimpleChanges) { 
    //when it gets userId it starts to track fit user in ngrx store
    this.store
            .select(state => state.user-list)                 
            .map(userList => userList[this.userId])
            .filter(user => !!user)
            .subscribe((user) => this.userId.next(user));
}

      

0


source







All Articles