dependency injection - Jak vyřešit injektované instance ve Vue.js pomocí TypeScriptu
Podle oficiálního dokumentu se zdá, že můžeme používat funkci dependency injection, pokud zůstaneme u objektově založené struktury.
Tady je moje otázka. Používám TypeScript k dosažení tohoto cíle (založeného na třídách). Plánuji použít Inversify jako IoC kontejner. Můj počáteční nápad byl něco takového:
DependencyConfig.ts:
import { Container } from "inversify";
import "reflect-metadata";
import Warrior from "./interfaces/Warrior";
import { Ninja } from "./models/Warrior";
let container = new Container();
container.bind<Warrior>(Symbol("Warrior")).to(Ninja);
export default container;
App.ts:
import container from "./DependencyConfig";
@Component({
name: "App",
provide: container
})
export default class App extends Vue {
}
Když jsem se podíval do vývojářské konzole svého prohlížeče, mohl jsem vidět, že container byl nastaven do pole _provided. Zde je Hello.ts, dětská komponenta App.ts:
Hello.ts:
@Component({
name: "Hello",
inject: [ "container" ]
})
export default class Hello extends Vue {
created (): void {
console.log(this);
}
}
Jelikož App.ts mohl přistupovat k Hello.ts přes vue-router, nezaregistroval Hello.ts jako dětskou komponentu. Očekával jsem, že se injektovaný kontejner objeví v _injected nebo něčím podobném. Nicméně jsem jej nemohl najít. Změnil jsem hodnotu vlastnosti inject z "container" na { "container": Symbol("Container") }, ale stále jsem jej nemohl najít.
Lokátor služeb:
Používání service locatoru místo páru provide/inject funguje dobře:
// App.ts
@Component({
name: "App"
})
export default class App extends Vue {
}
// Hello.ts
import container from "./DependencyConfig";
@Component({
name: "Hello"
})
export default class Hello extends Vue {
created (): void {
var ninja = container.get<Ninja>(Symbol("Warrior"));
console.log(ninja.name);
}
}
Nicméně zde chci vyhnout používání vzoru service locator. Přeskočil jsem něco při používání páru provide/inject pro injektování závislostí?
Odpověď č. 1
Našel jsem řešení. Pokud použijeme vue-class-component a vue-property-decorator, můžeme tohoto cíle dosáhnout - použitím páru provide/inject. Zde je můj úryvek kódu:
// App.vue
<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";
import SERVICE_IDENTIFIER from "./models/Identifiers";
import container from "./configs/DependencyConfigs";
@Component({
name: "App",
// Provides IoC container at the top level of VueComponent
provide: {
[SERVICE_IDENTIFIER.CONTAINER]: container
}
})
export default class App extends Vue {
}
</script>
V nejvyšší komponentě Vue, App.vue, poskytujeme instanci container, aby ji mohly využívat všechny její podřízené komponenty. Zde je jedna z jejích podřízených komponent, Ninja.vue:
// Ninja.vue
<script lang="ts">
import Vue from "vue";
// Imports both Component and Inject decorators from vue-property-decorator,
// instead of vue-class-component
import { Component, Inject } from "vue-property-decorator";
import { Container } from "inversify";
import SERVICE_IDENTIFIER from "../models/Identifiers";
import { Ninja as _Ninja } from "../models/Warrior";
@Component({
name: "Ninja"
})
export default class Ninja extends Vue {
public warrior: string;
public weapon: string;
// IoC container provided from App.ts is injected here
@Inject(SERVICE_IDENTIFIER.CONTAINER)
private _container: Container;
private _ninja: _Ninja;
created (): void {
this._ninja = this._container.get<_Ninja>(SERVICE_IDENTIFIER.WARRIOR);
this.warrior = this._ninja.name;
this.weapon = this._ninja.weapon.name;
}
}
</script>
Dětská komponenta používá dekorátor @Inject(Symbol) k vyřešení injektované instance container z App.vue.
O tomto jsem napsal blogový příspěvek jak v angličtině, tak v korejštině.
Doufám, že to pomůže
