我很确定我错过了一些东西。正如你在这里看到的,我只有一个订阅,而且在组件内部我使用 typeWriter 函数进行本地更改,但 UI 不会根据它进行更新。仅当我使用changeDetectorRef.detectChanges()时,它才起作用,当您进行本地更改时,它看起来不是最好的方法。
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { IconDefinition, faCopy } from '@fortawesome/free-solid-svg-icons';
import { HotToastService } from '@ngneat/hot-toast';
import { Store } from '@ngrx/store';
import { Subscription } from 'rxjs';
import { InitialState } from '../../../../../../store/store';
import { storeActions } from '../../../../../../store/store.actions';
import { selectPrinting } from '../../../../../../store/store.selectors';
import { MessageI } from './message.types';
@Component({
selector: 'app-message',
templateUrl: './message.component.html',
styleUrl: './message.component.scss',
})
export class MessageComponent implements OnInit, OnDestroy {
/**
* Chat object which contains properties {from & message}
*/
@Input() chat: MessageI;
private subscriptions: Subscription[] = [];
public printing$: boolean;
public copyIcon: IconDefinition = faCopy;
public copyIconStyle = {
dimensions: {
height: 20,
width: 20,
},
style: { color: 'white', cursor: 'pointer', width: 'max-content' },
};
public setIntervalID: number;
public printedMessage: string = '';
get imageUrl(): string {
return this.chat.from === 'You'
? 'assets/images/me.jpg'
: 'assets/images/cat.png';
}
constructor(
private toast: HotToastService,
private store: Store<{ store: InitialState }>
) {}
ngOnInit(): void {
this.subscriptions.push(
this.store.select(selectPrinting).subscribe((vl) => {
this.printing$ = vl;
})
);
if (this.chat.from === 'You') {
this.printedMessage = this.chat.message;
return;
}
this.typwriterEffect(50);
this.store.dispatch(storeActions.printingHandler());
}
ngOnDestroy(): void {
this.subscriptions.forEach((s) => s.unsubscribe());
}
copyMessage() {
this.toast.success('Copied to clipboard!', {
duration: 5000,
style: {
border: '1px solid #713200',
padding: '16px',
color: '#713200',
},
iconTheme: {
primary: '#713200',
secondary: '#FFFAEE',
},
});
navigator.clipboard.writeText(this.chat.message);
}
typwriterEffect(speed: number) {
// Has to be used from window otherwise theres typescript errors that it needs to be Nodejs.Timeout which prompts another error
// conflicts with Nodejs enviroments
this.setIntervalID = window.setInterval(() => {
if (
this.printedMessage.length !== this.chat.message.length &&
this.printing$
) {
this.printedMessage = this.chat.message.slice(
0,
this.printedMessage.length + 1
);
} else {
this.store.dispatch(storeActions.printingHandler());
clearInterval(this.setIntervalID);
}
}, speed);
}
}
发生这种情况是因为当您的可观察对象触发时,未触发更改检测周期。
解决这个问题的一种方法是使用 async pipeline 来确保每次您的 observable 触发时都会触发更改检测。
在您的示例中,您可以执行以下操作:
this.printing$ = this.store.select(selectPrinting)
代替:
this.subscriptions.push(
this.store.select(selectPrinting).subscribe((vl) => {
this.printing$ = vl;
})
);
在 HTML 模板中:
<ng-container *ngIf="printing$ | async as printing">
// the HTML code where printing is used,
// you can reference to it in the template as `printing`
</ng-container>
另请注意,按照惯例,仅命名
Observables
并带有尾随“$”