Sejak versi terbaru Angular, sistem kereaktifan primitif baharu telah dibangunkan dalam rangka kerja: isyarat!
Hari ini, dengan melihat ke belakang, kami menyedari bahawa kes penggunaan tertentu tidak dilindungi, dan jelas sekali pasukan Angular yang sangat reaktif akan memberikan kami pembantu untuk menampung kes penggunaan ini.
Apakah kes kegunaan ini? Apakah penyelesaian yang akan dilaksanakan dan bagaimanakah ia akan digunakan?
Mari kita mulakan dengan menggambarkan masalah ini.
Bayangkan kita ada sebakul buah dengan kuantiti tertentu.
Kuantiti diuruskan oleh komponen, yang memasukkan buah.
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); count = signal(1); updateQuantity(): void { this.count.update(prevCount => prevCount++); } }
Di sini pembolehubah mesti ditetapkan semula jika buah harga input berubah.
Penyelesaian mudah ialah menggunakan kesan
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); quantity = signal(1); countEffect(() => { this.fruit(); this.quantity.set(1); }, { allowSignalWrites: true }) updateQuantity(): void { this.quantity.update(prevCount => prevCount++); } }
Kod sebelumnya adalah amalan buruk. Kenapa ini soalan besar?
Kita perlu menetapkan pilihan signalWrites kepada benar untuk menetapkan kuantiti isyarat. Ini disebabkan salah tafsir masalah yang diberikan.
Dalam kes kami, kami ingin menyegerakkan dua pembolehubah yang, dalam pewujudan kami, dinyahsegerakkan
Kaunter tidak bergantung pada buah, yang merupakan sumber awal kami. Pada hakikatnya, di sini kita mempunyai keadaan komponen, yang sumber awalnya adalah buah dan selebihnya adalah terbitan buah.
Realisasikan masalah seperti berikut
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{fruitState().quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); fruitState = computed(() => ({ source: fruit(), quantity: signal(1), })); updateQuantity(): void { this.fruitState().quantity.update(prevCount => prevCount++); } }
Penciptaan ini sangat mengaitkan buah dengan kuantitinya.
Jadi sebaik sahaja buah berubah, fruitState pembolehubah yang dikira dikira semula secara automatik. Pengiraan semula ini mengembalikan objek dengan sifat kuantiti, iaitu isyarat yang dimulakan kepada 1.
Dengan mengembalikan isyarat, pembolehubah boleh dinaikkan pada klik dan hanya menetapkan semula apabila buah berubah.
Ia adalah corak yang agak mudah untuk disediakan, tetapi tidakkah kita boleh memudahkannya?
Dengan ketibaan Angular 19, fungsi baharu untuk mengira isyarat terbitan.
Sehingga kini, kami mempunyai fungsi yang dikira, tetapi fungsi ini mengembalikan Isyarat dan bukan WrittableSignal, yang mungkin praktikal dalam kes penggunaan kami sebelum ini untuk pembolehubah kuantiti.
Di sinilah LinkedSignal masuk. LinkedSignal, seperti namanya, membolehkan anda memautkan dua isyarat dengan kuat bersama-sama.
Jika kita kembali ke kes sebelumnya, fungsi ini akan membolehkan kita memudahkan kod seperti berikut:
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); quantity = linkedSignal({ source: fruit, computation: () => 1 }); updateQuantity(): void { this.quantity.update(prevCount => prevCount++); } }
Fungsi linkedSignal ditakrifkan seperti berikut:
linkedSignal(computation: () => D, options?: { equal?: ValueEqualityFn<NoInfer<D>>; }): WritableSignal<D>; linkedSignal(options: { source: () => S; computation: (source: NoInfer<S>, previous?: { source: NoInfer<S>; value: NoInfer<D>; }) => D; equal?: ValueEqualityFn<NoInfer<D>>; }): WritableSignal<D>;
Dalam takrif pertama, takrifan "disingkat", fungsi linkedSignal mengambil fungsi pengiraan sebagai parameter dan objek konfigurasi.
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); count = signal(1); updateQuantity(): void { this.count.update(prevCount => prevCount++); } }
Dalam contoh sebelumnya ini, kerana fungsi pengiraan bergantung kepada kuantiti sigal, apabila kuantiti berubah, fungsi pengiraan dinilai semula.
Dalam definisi kedua, kaedah linkedFunction mengambil objek sebagai parameter dengan tiga sifat
Bertentangan dengan fungsi pengiraan "disingkat", di sini fungsi pengiraan mengambil sebagai parameter nilai sumber dan "pendahuluan".
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); quantity = signal(1); countEffect(() => { this.fruit(); this.quantity.set(1); }, { allowSignalWrites: true }) updateQuantity(): void { this.quantity.update(prevCount => prevCount++); } }
Angular 19 akan memperkenalkan API baharu untuk pengambilan data mudah dan mendapatkan semula status pertanyaan (belum selesai dll), data dan ralat.
Bagi mereka yang agak biasa dengan rangka kerja, API baharu ini berfungsi sedikit seperti cangkuk useRessource.
Mari kita lihat contoh:
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{fruitState().quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); fruitState = computed(() => ({ source: fruit(), quantity: signal(1), })); updateQuantity(): void { this.fruitState().quantity.update(prevCount => prevCount++); } }
Terdapat beberapa perkara yang perlu diketahui tentang coretan kod ini
Terdapat beberapa perkara yang perlu diperhatikan dalam kod coretan ini:
Kesan berikut akan mencetak nilai tersebut
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); quantity = linkedSignal({ source: fruit, computation: () => 1 }); updateQuantity(): void { this.quantity.update(prevCount => prevCount++); } }
seperti yang dijelaskan di atas, secara lalai isyarat fruitId tidak dijejaki.
Jadi bagaimana anda memulakan semula permintaan http setiap kali nilai isyarat ini berubah, tetapi juga bagaimana anda membatalkan permintaan sebelumnya sekiranya nilai isyarat fruitId berubah dan tindak balas kepada permintaan sebelumnya tidak tiba?
Fungsi sumber mengambil sifat lain yang dipanggil permintaan.
Hartanah ini mengambil sebagai nilainya fungsi yang bergantung pada isyarat dan mengembalikan nilainya.
linkedSignal(computation: () => D, options?: { equal?: ValueEqualityFn<NoInfer<D>>; }): WritableSignal<D>; linkedSignal(options: { source: () => S; computation: (source: NoInfer<S>, previous?: { source: NoInfer<S>; value: NoInfer<D>; }) => D; equal?: ValueEqualityFn<NoInfer<D>>; }): WritableSignal<D>;
Seperti yang ditunjukkan dalam kod di atas, fungsi pemuat mengambil dua parameter
Jadi jika nilai isyarat fruitId berubah semasa httpRequest mendapatkan semula butiran buah, permintaan akan dibatalkan untuk melancarkan permintaan baharu.
Akhirnya, Angular juga telah memikirkan kemungkinan untuk menggabungkan api baharu ini dengan RxJs, membolehkan kami mendapat manfaat daripada kuasa pengendali Rx.
Kesalinghubungan dicapai menggunakan fungsi rxResource, yang ditakrifkan dengan cara yang sama seperti fungsi sumber.
Satu-satunya perbezaan ialah jenis pemulangan sifat pemuat, yang akan mengembalikan pemerhatian
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); count = signal(1); updateQuantity(): void { this.count.update(prevCount => prevCount++); } }
Di sini tidak perlu mempunyai abortSignal, pembatalan permintaan sebelumnya apabila nilai perubahan fruitId isyarat tersirat dalam fungsi rxResource dan tingkah laku akan sama dengan operator switchMap.
Atas ialah kandungan terperinci Peningkatan seterusnya dalam kereaktifan sudut. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!