Pinia/Vuex sowie Redux sind als „Single Source of Truth“ konzipiert, in der Sie einen oder mehrere Stores haben können, in denen Anwendungsdaten gespeichert werden können, die von überall abgerufen werden können.
Der Pinia-Store sieht so aus:
export let useProductsStore = defineStore('products', () => { let data = ref(products); function getList (params) { return someSearchStuffForProducts(params); } return {data, getList}; });
kann dann verwendet werden als:
let productsStore = useProductsStore(); console.log(data, data.value); productsStore.getList(params);
Wir können mehrere Geschäfte erstellen:
let usersStore = useUsersStore(); let productsStore = useProductsStore(); let basketStore = useBasketStore(); let favoritesStore = useFavoritesStore();
Stores können aufeinander verweisen:
export let useUsersStore = defineStore('users', () => { let productsStore = useProductsStore(); } export let useBasketsStore = defineStore('basket', () => { let productsStore = useProductsStore(); } //Et cetera
Schließlich sind Pinia/Vuex Tools, die die Möglichkeit bieten, im Staat gespeicherte Daten abzurufen und zu bearbeiten.
Aber es gibt noch einen anderen ausgereiften Ansatz: Manager-/Service-Kurse.
Das vorherige Beispiel kann wie folgt umgeschrieben werden:
//Define the "single source of truth" let store = { products: { /* ... */}, currentUser: { /* ... */}, userBasket: { /* ... */}, userFavorites: { /* ... */}, }; //Here goes manager classes class ProductsManager { constructor (params) { this.state = params.state; //... } getList (params) { return someSearchStuffForProducts(params); } } class UsersManager { constructor (params) { this.state = params.state; //Products manager is injected as a dependency this.productsManager = params.productsManager; //... } } class BasketManager { constructor (params) { this.state = params.state; //Products manager is injected as a dependency this.productsManager = params.productsManager; //... } } //Some config/initialization script export let DIC = {}; //Container for manager instances DIC.productsManager = new ProductsManager({state: store.products}); DIC.usersManager = new usersManager({ state: store.currentUser, productsManager: DIC.productsManager, }); DIC.basketManager = new BasketManager({ state: store.userBasket, productsManager: DIC.productsManager, }); //Usage import {DIC} from './config'; DIC.productsManager.getList(); DIC.basketManager.add(someProductId); DIC.basketManager.changeCount(someProductId, 3);
All dies kann einfach in TypeScript eingegeben werden, ohne dass zusätzliche Wrapper usw. erforderlich sind. ref()
Außerdem bietet es keine Abhängigkeitsinjektion: Sie können die Stores in der Konfiguration nicht initialisieren und einen Store genau in einen anderen injizieren, Sie müssen
useProductsStore() übergeben und so weiter.
Pinia fördert sogar zirkuläre Abhängigkeiten, was zu Spaghetti-Code mit schlechter Wartbarkeit führt
Warum sollte man also Pinia/Vuex dem bewährten Clean-OOP-Ansatz mit Managerklassen vorziehen? Ich habe Dutzende Stunden damit verbracht, ein Tutorial-Projekt meiner eigenen Erfindung zu schreiben und Pinia als „nächstes empfohlenes Vue-Zustandsmanagement“ zu verwenden, und jetzt bin ich versucht, alles in Manager-Klassen umzuschreiben, weil ich Pinia klobig und reichhaltig finde. Mir ist gerade eingefallen, dass ich vor ein paar Jahren ein weiteres Testprojekt geschrieben habe – mit Vue2 – und damals die Manager-Klasse verwendet habe – und alles verlief reibungslos. Habe ich etwas übersehen? Wird es ein Problem geben, wenn ich Pinia aufgebe?
类在 Vue 反应性中是二等公民,并且存在一些陷阱。它们无法在构造函数中绑定
this
,这将导致使用非反应式类实例反应式代理。他们无法有效地使用引用,因为这些引用是在记录但异常的方式。他们无法使用 get/set 访问器来计算引用。这些问题需要显式使用 Vue 反应性 API 以奇怪的方式编写类,或者以受限制的方式设计类,因此reactive(new MyClass)
不会阻止它工作正确。类不具备商店所具有的功能,例如对 Vue 开发工具、插件系统等的广泛支持。
类在 JavaScript 中也无法序列化,因此保存和恢复状态需要自定义逻辑,而不是像存储持久性插件中那样进行简单的 JSON(反)序列化。
依赖注入并不是类所独有的,并且可以以合适的方式执行,例如对于 Pinia 商店:
在许多情况下,最好处理 Pinia 存储可组合项而不是存储实例,因为这可以解决循环依赖关系,如果过早调用可组合项,循环依赖关系可能会成为问题。类也可能出现同样的问题,并且需要使用 DI 容器而不是直接使用类实例。
继承没有问题,因为可重用代码可以用 FP 而不是 OOP 来处理。 Vue 没有明确推广它,但使前者更惯用且使用起来更舒适。
TL;DR:坚持使用普通对象和 FP,因为这是 Vue 反应性设计的主要情况。