İlk olarak, bileşenler arasındaki ilişkileri anlamak için gerekenler. O zaman doğru iletişim yöntemini seçebilirsiniz. Bileşenler arasındaki iletişim için pratiğimde bildiğim ve kullandığım tüm yöntemleri açıklamaya çalışacağım.
Bileşenler arasında ne tür ilişkiler olabilir?
1. Ebeveyn> Çocuk
Girdi ile Veri Paylaşımı
Bu muhtemelen veri paylaşmanın en yaygın yöntemidir. @Input()
Verilerin şablondan geçirilmesine izin vermek için dekoratörü kullanarak çalışır .
parent.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'parent-component',
template: `
<child-component [childProperty]="parentProperty"></child-component>
`,
styleUrls: ['./parent.component.css']
})
export class ParentComponent{
parentProperty = "I come from parent"
constructor() { }
}
child.component.ts
import { Component, Input } from '@angular/core';
@Component({
selector: 'child-component',
template: `
Hi {{ childProperty }}
`,
styleUrls: ['./child.component.css']
})
export class ChildComponent {
@Input() childProperty: string;
constructor() { }
}
Bu çok basit bir yöntem. Kullanımı kolaydır. Ayrıca ngOnChanges'i kullanarak alt bileşendeki verilerdeki değişiklikleri yakalayabiliriz .
Ancak, bir nesneyi veri olarak kullanırsak ve bu nesnenin parametrelerini değiştirirsek, ona yapılan başvurunun değişmeyeceğini unutmayın. Bu nedenle, bir alt bileşende değiştirilmiş bir nesne almak istiyorsak, değişmez olmalıdır.
2. Çocuk> Ebeveyn
ViewChild ile Veri Paylaşma
ViewChild , bir bileşenin diğerine enjekte edilmesine izin vererek ebeveynin özniteliklerine ve işlevlerine erişmesini sağlar. Ancak bir uyarı, child
görünüm başlatılana kadar kullanılamayacak olmasıdır. Bu, alt öğeden veri almak için AfterViewInit yaşam döngüsü kancasını uygulamamız gerektiği anlamına gelir.
parent.component.ts
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from "../child/child.component";
@Component({
selector: 'parent-component',
template: `
Message: {{ message }}
<child-compnent></child-compnent>
`,
styleUrls: ['./parent.component.css']
})
export class ParentComponent implements AfterViewInit {
@ViewChild(ChildComponent) child;
constructor() { }
message:string;
ngAfterViewInit() {
this.message = this.child.message
}
}
child.component.ts
import { Component} from '@angular/core';
@Component({
selector: 'child-component',
template: `
`,
styleUrls: ['./child.component.css']
})
export class ChildComponent {
message = 'Hello!';
constructor() { }
}
Output () ve EventEmitter ile Veri Paylaşma
Veri paylaşmanın bir başka yolu, çocuk tarafından ebeveyn tarafından listelenebilecek veriler yayınlamaktır. Bu yaklaşım, düğme tıklamaları, form girişleri ve diğer kullanıcı olayları gibi şeylerde meydana gelen veri değişikliklerini paylaşmak istediğinizde idealdir.
parent.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'parent-component',
template: `
Message: {{message}}
<child-component (messageEvent)="receiveMessage($event)"></child-component>
`,
styleUrls: ['./parent.component.css']
})
export class ParentComponent {
constructor() { }
message:string;
receiveMessage($event) {
this.message = $event
}
}
child.component.ts
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'child-component',
template: `
<button (click)="sendMessage()">Send Message</button>
`,
styleUrls: ['./child.component.css']
})
export class ChildComponent {
message: string = "Hello!"
@Output() messageEvent = new EventEmitter<string>();
constructor() { }
sendMessage() {
this.messageEvent.emit(this.message)
}
}
3. Kardeşler
Çocuk> Ebeveyn> Çocuk
Kardeşler arasında iletişim kurmanın diğer yollarını açıklamaya çalışıyorum. Ancak yukarıdaki yöntemleri anlamanın yollarından birini zaten anlayabilirsiniz.
parent.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'parent-component',
template: `
Message: {{message}}
<child-one-component (messageEvent)="receiveMessage($event)"></child1-component>
<child-two-component [childMessage]="message"></child2-component>
`,
styleUrls: ['./parent.component.css']
})
export class ParentComponent {
constructor() { }
message: string;
receiveMessage($event) {
this.message = $event
}
}
çocuk one.component.ts
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'child-one-component',
template: `
<button (click)="sendMessage()">Send Message</button>
`,
styleUrls: ['./child-one.component.css']
})
export class ChildOneComponent {
message: string = "Hello!"
@Output() messageEvent = new EventEmitter<string>();
constructor() { }
sendMessage() {
this.messageEvent.emit(this.message)
}
}
çocuk two.component.ts
import { Component, Input } from '@angular/core';
@Component({
selector: 'child-two-component',
template: `
{{ message }}
`,
styleUrls: ['./child-two.component.css']
})
export class ChildTwoComponent {
@Input() childMessage: string;
constructor() { }
}
4. İlişkisiz Bileşenler
Aşağıda tarif ettiğim tüm yöntemler, bileşenler arasındaki ilişki için yukarıdaki tüm seçenekler için kullanılabilir. Ancak her birinin kendi avantajları ve dezavantajları vardır.
Verileri Hizmetle Paylaşma
Kardeşler, torunlar vb. Gibi doğrudan bağlantısı olmayan bileşenler arasında veri aktarırken, paylaşılan bir hizmet kullanmalısınız. Her zaman senkronize olması gereken veriler olduğunda, bu durumda RxJS BehaviorSubject'i çok yararlı buluyorum.
data.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable()
export class DataService {
private messageSource = new BehaviorSubject('default message');
currentMessage = this.messageSource.asObservable();
constructor() { }
changeMessage(message: string) {
this.messageSource.next(message)
}
}
first.component.ts
import { Component, OnInit } from '@angular/core';
import { DataService } from "../data.service";
@Component({
selector: 'first-componennt',
template: `
{{message}}
`,
styleUrls: ['./first.component.css']
})
export class FirstComponent implements OnInit {
message:string;
constructor(private data: DataService) {
// The approach in Angular 6 is to declare in constructor
this.data.currentMessage.subscribe(message => this.message = message);
}
ngOnInit() {
this.data.currentMessage.subscribe(message => this.message = message)
}
}
second.component.ts
import { Component, OnInit } from '@angular/core';
import { DataService } from "../data.service";
@Component({
selector: 'second-component',
template: `
{{message}}
<button (click)="newMessage()">New Message</button>
`,
styleUrls: ['./second.component.css']
})
export class SecondComponent implements OnInit {
message:string;
constructor(private data: DataService) { }
ngOnInit() {
this.data.currentMessage.subscribe(message => this.message = message)
}
newMessage() {
this.data.changeMessage("Hello from Second Component")
}
}
Bir Rota ile Veri Paylaşma
Bazen sadece bileşen arasında basit veri iletmekle kalmaz, aynı zamanda sayfanın bazı durumlarını da kaydedebilirsiniz. Örneğin, çevrimiçi pazarda bir miktar filtre kaydetmek ve ardından bu bağlantıyı kopyalayıp bir arkadaşınıza göndermek istiyoruz. Sayfayı bizimle aynı durumda açmasını bekliyoruz. Bunu yapmanın ilk ve muhtemelen en hızlı yolu sorgu parametrelerini kullanmak olacaktır .
Sorgu parametreleri daha çizgisinde bakmak /people?id=
nerede id
şey eşit olabilir ve istediğiniz kadar birçok parametre olarak sahip olabilir. Sorgu parametreleri ve işareti karakteriyle ayrılır.
Sorgu parametreleriyle çalışırken, bunları yollar dosyanızda tanımlamanız gerekmez ve bunlara parametreler adı verilebilir. Örneğin, aşağıdaki kodu alın:
page1.component.ts
import {Component} from "@angular/core";
import {Router, NavigationExtras} from "@angular/router";
@Component({
selector: "page1",
template: `
<button (click)="onTap()">Navigate to page2</button>
`,
})
export class Page1Component {
public constructor(private router: Router) { }
public onTap() {
let navigationExtras: NavigationExtras = {
queryParams: {
"firstname": "Nic",
"lastname": "Raboy"
}
};
this.router.navigate(["page2"], navigationExtras);
}
}
Alıcı sayfada, aşağıdaki gibi bu sorgu parametrelerini alırsınız:
page2.component.ts
import {Component} from "@angular/core";
import {ActivatedRoute} from "@angular/router";
@Component({
selector: "page2",
template: `
<span>{{firstname}}</span>
<span>{{lastname}}</span>
`,
})
export class Page2Component {
firstname: string;
lastname: string;
public constructor(private route: ActivatedRoute) {
this.route.queryParams.subscribe(params => {
this.firstname = params["firstname"];
this.lastname = params["lastname"];
});
}
}
NgRx
Daha karmaşık ancak daha güçlü olan son yol NgRx kullanmaktır . Bu kütüphane veri paylaşımı için değildir; güçlü bir devlet yönetimi kütüphanesidir. Kısa bir örnekte nasıl kullanılacağını açıklayamıyorum, ancak resmi siteye gidip onunla ilgili belgeleri okuyabilirsiniz.
Bana göre NgRx Store birden fazla sorunu çözüyor. Örneğin, gözlemlenebilirlerle ilgilenmeniz gerektiğinde ve gözlemlenebilir bazı verilerin sorumluluğu farklı bileşenler arasında paylaşıldığında, mağaza eylemleri ve redüktör veri değişikliklerinin her zaman "doğru şekilde" yapılmasını sağlar.
Ayrıca HTTP isteklerinin önbelleğe alınması için güvenilir bir çözüm sunar. Yaptığınız isteğin henüz depolanmış bir yanıtı olmadığını doğrulayabilmeniz için istekleri ve yanıtlarını depolayabileceksiniz.
NgRx hakkında okuyabilir ve uygulamanızda buna ihtiyacınız olup olmadığını anlayabilirsiniz:
Son olarak, veri paylaşım yöntemlerinden bazılarını seçmeden önce, bu verilerin gelecekte nasıl kullanılacağını anlamanız gerektiğini söylemek istiyorum. Yani belki şimdi sadece bir @Input
kullanıcı adı ve soyadı paylaşmak için sadece bir dekoratör kullanabilirsiniz . Ardından, kullanıcı hakkında daha fazla bilgi gerektiren yeni bir bileşen veya yeni bir modül (örneğin, bir yönetici paneli) ekleyeceksiniz. Bu, bir hizmeti kullanıcı verileri için kullanmanın daha iyi bir yolu veya veri paylaşmanın başka bir yolu olabileceği anlamına gelir. Veri paylaşımını uygulamaya başlamadan önce daha fazla düşünmeniz gerekir.