Mengapakah BehaviorSubject saya mengemas kini apabila saya tidak menghantar nilai baharu kepada kaedah seterusnya()?
P粉321584263
P粉321584263 2024-03-21 22:58:22
0
1
376

Saya cuba membuat aplikasi TODO yang mudah menggunakan RXJS. Saya mempunyai pangkalan data olok-olok pelayan JSON yang mengandungi tugas TODO.

Jadi saya berakhir dengan TasksService ini:

@Injectable({
  providedIn: 'root'
})
export class TasksService
{
  private _tasks : ITask[] = [];
  private _tasks$: BehaviorSubject<ITask[]> = new BehaviorSubject<ITask[]>([]);
  constructor (private _http: HttpClient) { }

  public getTasks()
  {
    this.getTasksObservableFromDb().pipe(
      tap(
        (tasks) => 
        {
          this._tasks = tasks;
          this._tasks$.next(tasks);
        }
      )
    ).subscribe();

    return this._tasks$;
  }

  public addTask(task: ITask)
  {
    this._tasks.push(task);
    this._tasks$.next(this._tasks);
  }

  private getTasksObservableFromDb(): Observable<any>
  {
    return this._http.get<any>('http://127.0.0.1:3000/tasks');
  }

Apabila saya menambah tugasan, saya tidak mahu menerbitkannya ke pelayan serta-merta. Oleh itu, apabila saya mendapat tugas daripada pelayan, saya menyimpannya ke harta _tasks dan kemudian menghantarnya ke kaedah next() saya _tasks$:BehaviorSubject . Kerana kemudian saya mahu menerbitkan tugasan saya secara berkelompok ke pelayan dan sekarang saya hanya mahu mereka dipaparkan dengan betul dalam Angular.

Dalam AppComponent saya, saya mendapat tugasan dan menetapkannya kepada harta tugas saya.

export class AppComponent implements OnInit
{
  public tasks!:BehaviorSubject<ITask[]>;
  constructor (private _tasksService: TasksService)
  {}
  ngOnInit(): void
  {
    console.log('OnInit');
    this.tasks = this._tasksService.getTasks();
  }

  public addTask()
  {
    this._tasksService.addTask(
      {
        id: crypto.randomUUID(),
        isImportant: true,
        text: 'Added task'
      }
    );
  }
}

Dalam templat HTML saya, saya menggunakan paip async sebagai atribut tugas saya dan memaparkan tugas saya:

<ng-container *ngFor="let task of tasks | async">
    {{task.text}}
    {{task.id}}
</ng-container>
<button type="button" (click)="addTask()">Add Task</button>

Tetapi kemudian saya secara tidak sengaja memadamkan baris ini dalam TaskService saya: this._tasks$.next(this._tasks);

Jadi kaedah saya sekarang kelihatan seperti ini:

public addTask(task: ITask)
  {
    this._tasks.push(task);
  }

Tetapi menambah tugas masih berfungsi! Walaupun saya tidak menghantar pelbagai tugasan baharu kepada BehaviorSubject saya, Angular memaparkan tugasan yang baru ditambah.

Jadi saya memutuskan untuk merekodkan nilai dalam tugas saya! : BehaviorSubject<ITask[]> dalam kelas AppComponent saya:

public addTask()
  {
    this._tasksService.addTask(
      {
        id: crypto.randomUUID(),
        isImportant: true,
        text: 'Added task'
      }
    );

    this.tasks.pipe(tap((value) => console.log(value)
    )).subscribe();
  }

dan tugasan ditambah seperti yang diharapkan - setiap kali anda mendapat tatasusunan yang mengandungi satu tugas:

Array(3) [ {…}, {…}, {…} ] <- Add task button is clicked 
Array(4) [ {…}, {…}, {…}, {…} ] <- Add task button is clicked 
Array(5) [ {…}, {…}, {…}, {…}, {…} ] <- Add task button is clicked

Tetapi apabila saya mengembalikan baris ini kepada kaedah addTask dalam TaskService: this._tasks$.next(this._tasks);

Saya mendapat log ini:

Array(3) [ {…}, {…}, {…} ] <- Add task button is clicked -> one task is added
Array(4) [ {…}, {…}, {…}, {…} ] <- Add task button is clicked -> one task is added
Array(4) [ {…}, {…}, {…}, {…} ] <- I get the same array 
Array(5) [ {…}, {…}, {…}, {…}, {…} ] <- Add task button is clicked -> one task is added
Array(5) [ {…}, {…}, {…}, {…}, {…} ] <- I get the same array 
Array(5) [ {…}, {…}, {…}, {…}, {…} ] <- I get the same array once again

Jadi saya agak tersesat mengapa yang boleh diperhatikan berkelakuan seperti ini... mungkin saya tidak faham sepenuhnya kaedah seterusnya()?

P粉321584263
P粉321584263

membalas semua(1)
P粉080643975

Setakat yang saya faham, terdapat dua masalah dengan kod ini. Pertama, anda tidak tahu mengapa log konsol mempunyai pendua. Kedua, walaupun anda tidak memanggil ".next()" pada subjek tingkah laku, anda tidak tahu mengapa paparan dikemas kini.

Mari kita mulakan dengan yang pertama.

Anda perlu memahami cara rxjs observables dan BehaviorSubjects berfungsi. Pemerhatian biasa, apabila anda melanggannya, akan menunggu nilai tertentu untuk dipancarkan, dan kemudian setiap kali itu berlaku, ia akan memanggil operasi yang anda lampirkan padanya. Contohnya:

exampleSubject = new Subject();

ngOnInit(): void {
    this.exampleSubject.pipe(
        tap(console.log)
    ).subscribe();
}

emitValue() {
    this.exampleSubject.next("text");
}

Sekarang sila ambil perhatian bahawa dalam kod ini kami hanya melanggan sekali dalam ngOnInit. Walaupun begitu, console.log dipanggil setiap kali kaedah emitValue() dipanggil (cth. daripada butang). Ini kerana langganan kekal sehingga berhenti melanggan. Ini bermakna bahawa operasi akan dipanggil setiap kali next() dipanggil pada topik.

Jadi apa yang berlaku apabila anda melanggan beberapa kali? Jom cuba:

exampleSubject = new Subject();

ngOnInit(): void {
    subscribeToSubject(); // 1st
    subscribeToSubject(); // 2nd
    subscribeToSubject(); // 3rd
    this.emitValue();
}

emitValue() {
    this.exampleSubject.next("text");
}

subscribeToSubject() {
    this.exampleSubject.pipe(
        tap(console.log)
    ).subscribe();
}

Kami melanggan topik 3 kali dan kini apabila nilai dikeluarkan, log konsol dipanggil 3 kali. Ia dipanggil untuk setiap langganan yang anda buat.

Kini apabila kami melihat contoh anda, langganan ditambah setiap kali butang addTask diklik. Itulah sebabnya setiap kali anda menambah tugasan, terdapat log konsol tambahan. Tetapi hei, dalam contoh pertama anda, apabila anda mengalih keluar .next() anda mempunyai beberapa log konsol walaupun anda tidak mengeluarkan sebarang nilai, mengapa begitu? Sekarang kita sampai ke BehaviorSubject. Ini adalah topik istimewa yang mengekalkan nilainya dan mengeluarkannya sebaik sahaja anda melanggan. Dan ia juga memancarkan setiap kali anda memanggil .next() tetapi anda tidak berbuat demikian, jadi itulah sebabnya ia memanggil 1 log konsol setiap kali anda melanggan.

Apa yang patut anda lakukan ialah hubungi

this.tasks.pipe(tap((value) => console.log(value)
)).subscribe();

Hanya sekali, cth. dalam ngOnInit()

Okay, sekarang kita masuk fasa kedua

Ini sangat mudah tetapi memerlukan sedikit pengetahuan tentang cara rujukan berfungsi.

Dalam perkhidmatan anda, anda meletakkan keseluruhan tatasusunan tugas ke dalam BehaviorSubject. Malah, subjek ini memegang rujukan kepada tatasusunan ini. Ini bermakna setiap kali anda menolak nilai baharu ke dalam tatasusunan, BehaviorSubject juga akan memilikinya. Inilah yang berlaku, apabila anda memanggil kaedah addTask, nilai baharu ditolak ke tatasusunan tugas dan BehaviorSubject anda juga memilikinya.

Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan
Tentang kita Penafian Sitemap
Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!