Bağımlılık Enjeksiyonu
Bağımlılık Enjeksiyonuna Giriş
Servislerin kaydedilip bileşenlerden çözümlenmesi; kayıttan kullanıma tam örnek ve DI hata kodları; JSX ile ve JSX'siz.
MotifJS bütünleşik bir bağımlılık enjeksiyonu (DI) sistemi içerir. Servisleri uygulama başlarken kaydeder, sonra bileşenlerden veya başka servislerden çözümlersiniz (resolve). Servis, bileşenler arasında paylaşılan durumu ve işi tutan bir sınıf ya da değerdir. Bileşen servisi kendisi kurmaz, sağlayıcıdan (ServiceProvider) ister; sağlayıcı kaydın yaşam süresine göre ya aynı örneği ya da yeni bir örnek verir.
Kayıttan kullanıma
Servisler Application.CreateBuilder()'ın services koleksiyonuna, build()'den önce kaydedilir. addSingleton(token, { useClass }) sınıfı tek örnekli kaydeder; startup: true verilen singleton bir bileşen istemeden app.run() başında oluşturulur. Örnekteki iki kayıt (Bileşenler sayfasındaki NotesService ve SettingsService):
import { Application } from "@motifx/core";
import { NotesService } from "./services/notes";
import { SettingsService } from "./services/settings";
const builder = Application.CreateBuilder();
builder.services.addSingleton(NotesService, { useClass: NotesService });
builder.services.addSingleton(SettingsService, { useClass: SettingsService, startup: true });
const app = builder.build();
import { Application } from "@motifx/core";
import { NotesService } from "./services/notes";
import { SettingsService } from "./services/settings";
const builder = Application.CreateBuilder();
builder.services.addSingleton(NotesService, { useClass: NotesService });
builder.services.addSingleton(SettingsService, { useClass: SettingsService, startup: true });
const app = builder.build();
Bileşen kayıtlı bir servisi sağlayıcıdan alır: sınıf bileşeni ve Options nesnesi this.getService(token), fonksiyon bileşeni FromService(token) kullanır. Servisin reaktif durumu bir getter içinde okunduğunda bağ, durum değiştikçe yenilenir. Örnekteki FolderBadge bir klasördeki not sayısını gösterir:
import { Component } from "@motifx/core";
import { NotesService, type Folder } from "../services/notes";
export class FolderBadge extends Component<HTMLSpanElement, { folder: Folder }> {
notes = this.getService(NotesService)!;
override onConfigured() {
this.class.add("badge");
}
override view() {
return <>{() => this.notes.count(this.props.folder)}</>;
}
}
import { FromService } from "@motifx/core";
import { NotesService, type Folder } from "../services/notes";
export function FolderBadge(props: { folder: Folder }) {
const notes = FromService(NotesService)!;
return <span class="badge">{() => notes.count(props.folder)}</span>;
}
import { motifOptions } from "@motifx/core";
import { NotesService, type Folder } from "../services/notes";
export const FolderBadge = (props: { folder: Folder }) => motifOptions({
el: "span",
get notes() {
return this.getService(NotesService)!;
},
onConfigured() {
this.class.add("badge");
},
view() {
return <>{() => this.notes.count(props.folder)}</>;
},
});
import { Component, ComponentBase, motifComponent } from "@motifx/core";
import { NotesService, type Folder } from "../services/notes";
export class FolderBadge extends Component<HTMLSpanElement, { folder: Folder }> {
static override elementTag = "span";
notes = this.getService(NotesService)!;
override onConfigured() {
this.class.add("badge");
}
override view() {
return motifComponent("text", (node: ComponentBase) => node.bindings.text(() => this.notes.count(this.props.folder)));
}
}
import { ComponentBase, FromService, motifComponent } from "@motifx/core";
import { NotesService, type Folder } from "../services/notes";
export function FolderBadge(props: { folder: Folder }) {
const notes = FromService(NotesService)!;
return motifComponent("span", (badge: ComponentBase) => {
badge.class.add("badge");
badge.controls.add(motifComponent("text", (node: ComponentBase) => node.bindings.text(() => notes.count(props.folder))));
});
}
import { ComponentBase, motifComponent, motifOptions } from "@motifx/core";
import { NotesService, type Folder } from "../services/notes";
export const FolderBadge = (props: { folder: Folder }) => motifOptions({
el: "span",
get notes() {
return this.getService(NotesService)!;
},
onConfigured() {
this.class.add("badge");
},
view() {
return motifComponent("text", (node: ComponentBase) => node.bindings.text(() => this.notes.count(props.folder)));
},
});
import { Component } from "@motifx/core";
import { NotesService } from "../services/notes";
export class FolderBadge extends Component {
static elementTag = "span";
notes = this.getService(NotesService);
onConfigured() {
this.class.add("badge");
}
view() {
return <>{() => this.notes.count(this.props.folder)}</>;
}
}
import { FromService } from "@motifx/core";
import { NotesService } from "../services/notes";
export function FolderBadge(props) {
const notes = FromService(NotesService);
return <span class="badge">{() => notes.count(props.folder)}</span>;
}
import { motifOptions } from "@motifx/core";
import { NotesService } from "../services/notes";
export const FolderBadge = (props) => motifOptions({
el: "span",
get notes() {
return this.getService(NotesService);
},
onConfigured() {
this.class.add("badge");
},
view() {
return <>{() => this.notes.count(props.folder)}</>;
},
});
import { Component, motifComponent } from "@motifx/core";
import { NotesService } from "../services/notes";
export class FolderBadge extends Component {
static elementTag = "span";
notes = this.getService(NotesService);
onConfigured() {
this.class.add("badge");
}
view() {
return motifComponent("text", (node) => node.bindings.text(() => this.notes.count(this.props.folder)));
}
}
import { FromService, motifComponent } from "@motifx/core";
import { NotesService } from "../services/notes";
export function FolderBadge(props) {
const notes = FromService(NotesService);
return motifComponent("span", (badge) => {
badge.class.add("badge");
badge.controls.add(motifComponent("text", (node) => node.bindings.text(() => notes.count(props.folder))));
});
}
import { motifComponent, motifOptions } from "@motifx/core";
import { NotesService } from "../services/notes";
export const FolderBadge = (props) => motifOptions({
el: "span",
get notes() {
return this.getService(NotesService);
},
onConfigured() {
this.class.add("badge");
},
view() {
return motifComponent("text", (node) => node.bindings.text(() => this.notes.count(props.folder)));
},
});
Bileşen etiketiyle kullanılır:
<RouterLink to="/notes" activeClass="active">Tüm notlar <FolderBadge folder="notes" /></RouterLink>
const all = motifComponent(RouterLink, {
to: "/notes",
activeClass: "active",
childs: [motifComponent("text", (node: ComponentBase) => node.setText("Tüm notlar ")), motifComponent(FolderBadge, { folder: "notes" })],
});
<RouterLink to="/notes" activeClass="active">Tüm notlar <FolderBadge folder="notes" /></RouterLink>
const all = motifComponent(RouterLink, {
to: "/notes",
activeClass: "active",
childs: [motifComponent("text", (node) => node.setText("Tüm notlar ")), motifComponent(FolderBadge, { folder: "notes" })],
});
Singleton kaydedilmiş bir servisi isteyen her bileşen aynı örneği alır. Servis durumunu reactive bir nesnede tutuyorsa bir bileşenin yaptığı değişiklik (örneğin notes.create()) o durumu okuyan bütün bağları yeniler; ayrıca bir olay ya da bildirim gerekmez.
Fonksiyon bileşeninin this'i olmadığı için FromService servisi uygulamanın sağlayıcısından alır; scoped bir servis için bu da güncel gezinmenin handle'ını verir. Ayrıntılar Servis Çözümleme, kaydın diğer biçimleri ve @Injectable ile otomatik kayıt Servis Kaydı, bir servisin ne kadar yaşadığı Yaşam Süreleri ve Kapsamlar sayfasındadır.
DI hata kodları
Fırlatılan kodlar çağrıyı yapan satırda hata olarak gelir; uyarılar yalnız geliştirme kipinde konsola ve DevTools uyarı listesine yazılır, errorHandler dinleyicilerine gitmez (bkz. Hata Yönetimi). Bütün kodlar Hata ve Uyarı Kodları sayfasındadır:
| Kod | Ne zaman |
|---|---|
MJX401 |
Kayıtlı olmayan bir token get, getAsync ya da inject ile istendi; fırlatılır. |
MJX402 |
Async fabrika ya da Promise ile kaydedilmiş bir servis get ile istendi (startup servis dahil); fırlatılır, getAsync kullanılır. |
MJX403 |
Kayıt tanımı geçersiz; fırlatılır. |
MJX404 |
Döngüsel bağımlılık; fırlatılır. |
MJX405 |
İkinci bir ApplicationBuilder kuruldu; fırlatılır. |
MJX406 |
app.run seçiciyle verilen host elemanını bulamadı; fırlatılır. |
MJX407 |
getService bileşen için bir sağlayıcı bulamadı; geliştirme kipinde uyarı, null döner. |
MJX408 |
getService çözümlemesi hata verdi; geliştirme kipinde uyarı, null döner. |
MJX409 |
inject bir servis kurulumunun dışında çağrıldı; fırlatılır. |
MJX410 |
Bir kayıtta birden çok kaynak verildi; geliştirme kipinde uyarı, öncelik useValue > useFactory > useClass. |
MJX411 |
deps bir dizi değil; geliştirme kipinde uyarı, geçersiz deps yok sayılır. |
MJX413 |
Kurulamayan bir fonksiyon (ok fonksiyonu, async fonksiyon, nesne metodu) sınıf olarak kaydedildi; kayıt satırında fırlatılır. |
MJX414 |
FromService çözümleyemedi; geliştirme kipinde uyarı, null döner. |
MJX415 |
startup singleton olmayan bir kayda verildi; geliştirme kipinde uyarı, servis ilk çözümlemede oluşturulur. |
Sonraki adım
Servislerin nasıl kaydedildiğini öğrenmek için Servis Kaydı bölümüne geçin.