IT이야기

관측 가능으로 각도 2 변경 감지

cyworld 2022. 3. 19. 12:06
반응형

관측 가능으로 각도 2 변경 감지

나는 보통 기존의 질문들을 훑어보는 것만으로 내가 잘못하고 있는 것을 가까스로 찾지만, 여기서는 아무것도 도움이 되지 않았다.

NeDB 스토어의 내용을 나열하고 업데이트하는 간단한 Ng2 모듈로 작업하고 있다.

명심해, 나는 NeDB 스토어에 문제가 없어. 나는 그것이 올바르게 업데이트되고, 처음에 올바르게 로딩된다는 것을 확인했어. 그래서 내가 가지고 있는 문제들은 다른 곳에 있어.

내가 가지고 있는 문제는 다음과 같다.

"비동기 파이프가 작동하지 않는다"


나는 이 모듈을 가지고 있다.

@NgModule({
    imports: [CommonModule],
    exports: [],
    declarations: [WikiComponent],
    providers: [WikiDbService],
})
export class WikiModule { }

나는 이 구성 요소를 가지고 있다.

@Component({
    selector: 'wiki',
    templateUrl: './wiki.component.html'
})
export class WikiComponent implements OnInit {

    items: Observable<WikiItem[]>;

    constructor(private _db : WikiDbService) { }

    ngOnInit() {
        this.items = this._db.items;
        this.items.subscribe({
            next: x => console.log("got value", x),
            error: e => console.error("observable error", e),
            complete: () => console.log("done")
        });
    }
}

나는 이 템플릿이 있다.

<p>{{items | async | json}}</p>
<ul>
    <li *ngFor="let item of (items | async)">{{item.name}}</li>
</ul>
<input #newName (keyup)="0">
<button (click)="_db.addByName(newName.value)">ADD</button>

그리고 나는 이 서비스를 가지고 있다.

@Injectable()
export class WikiDbService {
    private sub: BehaviorSubject<WikiItem[]> = new BehaviorSubject<WikiItem[]>([]);
    private db: DataStore;
    public items: Observable<WikiItem[]> = this.sub.asObservable();
    constructor() {
        console.log("BehaviorSubject", this.sub);
        console.log("Observable", this.items);
        this.db = new DataStore(
            { 
                filename: path.join(app.getAppPath(),"wiki.db"),
                autoload: true,
                onload:
                (err)=>{
                    if(!err) {
                        this.db.find<WikiItem>({},
                        (e,docs) => {
                            if(!e) {
                                this.sub.next(docs);
                            }
                        })
                    }
                }
            });
    }

    public add(v: WikiItem) {
        this.db.insert(
            v,
            (e, nDoc) =>
            {
                if(!e) {
                    this.sub.next([...this.sub.getValue(),nDoc]);
                }
            }
        )
    }
    public addByName(str:string) {
        this.add({name: str, _id: undefined});
    }
}

비어 있지 않은 영구 저장소를 사용하여 구성 요소로 라우팅할 때 다음 콘솔 로그(구성 요소의 OnInit 메서드의 로그에 대응함)를 얻는다.

got value > [] (wiki.component.ts:20)
got value > [Object, Object, Object, Object] (wiki.component.ts:20)

그러나 내 DOM은 다음과 같이 유지된다.

<wiki>
    <p>[]</p>
    <ul>
        <!--template bindings={
          "ng-reflect-ng-for-of": ""
        }-->
    </ul>
    <input>
    <button>ADD</button>
</wiki>

그래서 내가 관찰할 수 있는 것에 대한 수동 구독이 효과가 있고, 나에게 가치를 가져다 준다.하지만 비동기 파이프는 그것들을 얻지 못한다.

내가 여기서 뭐 잘못하고 있는 거야, 아니면 벌레야?


편집

12/19/16 오후 3시 45분

ngFor지시어는 "종목의 | 비동기" 이었는데, 비동기 파이프가 내가 관찰할 수 있는 범위가 아니라 항목까지 범위가 정해져 있어서 괄호를 붙였지만 결과는 변함이 없었다.이것은 그 문제와 관련이 없다.

12/20/16 오후 3.06시

@olsn의 조언에 따라 구성 요소의 초기화items템플릿이 Observable에 가입되어 있는지 확인하기 위해 자동 로그가 있는 속성.

그래요.내 생각에 그것은 변화를 감지하는 것으로 귀결된다.제목 수정.

이 비트 정보 추가: 내 구성 요소도 이와 같음(편집된 변경 사항)

@Component({
    selector: 'wiki',
    templateUrl: './wiki.component.html',
    changeDetection: ChangeDetectionStrategy.OnPush // <=== I've read this might help. It doesn't.
})
export class WikiComponent implements OnInit {

    items: Observable<WikiItem[]> = this._db.items //
        .do(x => console.log("got value", x))      // <== new initialization, with a stream
        .publishReplay().refCount();               //

    constructor(private _db : WikiDbService, private _cd: ChangeDetectorRef) { }

    ngOnInit() {
                      // <=== moved items initialization
    }

    reload() : void {
        this._cd.markForCheck(); // <== added a button to force the change detector to react. Does not do anything.
    }
}

템플릿에 이 추가 기능 포함:

<button (click)="reload()">REFRESH</button>

해결책

@osln은 정답을 말했다.

문제는 근본적으로 가입이나 변경사항 탐지가 문제가 아니라, 내 탓이었다.sub.next콜백은 외부 도서관에 주어졌고, 그것은 구체적으로 내가 앵글 영역 밖에서 그것을 하고 있다는 것을 의미했다.

NgZone 호출을 통해 Angular tround로 강제로 돌려보내는 것이 이 문제를 해결하는 방법이었다.

고마워 @osln.

ngInit 에 항목 개체를 초기화하고 임시 로그를 스트림에 직접 추가하십시오. 이렇게 하면 현재 로그는 완전히 다른 스트림에서 실행되므로 템플릿이 스트림에 실제로 구독되는지 알 수 있다.

@Component({
    selector: 'wiki',
    templateUrl: './wiki.component.html'
})
export class WikiComponent implements OnInit {

    items: Observable<WikiItem[]> = this._db.items
        .do(x => console.log("got value", x)
        // if items is not a Behavior- or ReplaySubject or ReplayObservable, also add the following:
        .publishReplay()
        .refCount(); 

    constructor(private _db : WikiDbService) { }

    ngOnInit() {
        // ..nothing to do here
    }
}

또한 데이터 복구 작업을NgZone.run:

먼저 DbService에 주입하십시오.private ngZone: NgZone(출처)@angular/core() 그리고 나서 그냥 사용하는 대신this.sub.next(docs);, 사용:

this.ngZone.run(() => this.sub.next(docs));

(추가 호출에도 해당)

참조URL: https://stackoverflow.com/questions/41224671/angular-2-change-detection-with-observables

반응형