为什么 Pinia/Vuex 比服务类的经典方法更受欢迎?

问题描述 投票:0回答:1

Pinia/Vuex

Pinia/Vuex 以及 Redux 旨在成为“单一事实来源”,您可以在其中拥有一个或多个存储应用程序数据的商店,这些数据可从任何地方获得。

Pinia 商店看起来像这样:

export let useProductsStore = defineStore('products', () => {
    let data = ref(products);

    function getList (params) {
        return someSearchStuffForProducts(params);
    }

    return {data, getList};
});

然后可以用作:

let productsStore = useProductsStore();
console.log(data, data.value);
productsStore.getList(params);

我们可以创建多个商店:

let usersStore     = useUsersStore();
let productsStore  = useProductsStore();
let basketStore    = useBasketStore();
let favoritesStore = useFavoritesStore();

店铺可以互相参考:

export let useUsersStore = defineStore('users', () => {
    let productsStore = useProductsStore();
}

export let useBasketsStore = defineStore('basket', () => {
    let productsStore = useProductsStore();
}

//Et cetera

最后,Pinia/Vuex 是提供检索和操作存储在状态中的数据的能力的工具。

经理/服务类

但是还有另一种方法,行之有效的方法:管理器/服务类。

前面的例子可以改写为:

//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);

所有这些都可以在 TypeScript 中轻松输入,无需额外的包装器、

ref()

讨论

据我所知,Pinia 看起来像是“重新发明轮子”:以笨拙的方式编写相同的功能。

此外,它不提供依赖注入:您不能在配置中初始化商店并准确地将一个商店注入另一个商店,您必须通过

useProductsStore()
等将依赖项硬编码到商店中。

继承或任何其他面向对象的东西也是不可能的。

Pinia 甚至 促进 循环依赖,这导致了意大利面条式的代码,可维护性很差。

那么,毕竟,为什么人们更喜欢 Pinia/Vuex 而不是经过实战检验的、带有管理器类的干净的 OOP 方法?我已经用了几十个小时来编写我自己发明的教程项目,使用 Pinia 作为“下一个推荐的 Vue 状态管理”,现在我很想将所有内容重写到管理器类中,因为我发现 Pinia 笨拙且废弃。我只记得几年前我正在编写另一个测试项目 - 使用 Vue2 - 当时我使用了管理器类 - 一切都很顺利。我忽略了什么吗?如果我放弃 Pinia 会有问题吗?

vue.js vuex pinia
1个回答
2
投票

类是 Vue 反应性中的二等公民,并且有一些陷阱。他们不能在构造函数中绑定

this
,这将导致使用非反应性类实例而不是反应性代理。他们 无法有效地使用 refs ,因为这些 refs 以 记录但异常的方式展开 。他们不能对计算引用使用 get/set 访问器。这些问题要求要么通过显式使用 Vue 反应性 API 以奇怪的方式编写类,要么以受限的方式设计类,因此
reactive(new MyClass)
不会阻止它正常工作。

类没有商店所具有的功能,例如对 Vue 开发工具、插件系统等的广泛支持

依赖注入不是类独有的,可以以合适的方式执行,例如对于 Pinia 商店:

const basketManagerStore = defineStore({
  state: () => ({ _getFoo: null }),
  getters: { 
    foo: state => state._getFoo()
  },
  actions: {
    setFoo(getFoo) {
      this._getFoo = getFoo;
    }
  }
});

basketManagerStore.setFoo(useSomeFooStore);

在许多情况下,最好处理 Pinia 存储可组合项而不是存储实例,因为这解决了循环依赖性问题,如果过早调用可组合项可能会出现问题。同样的问题可能出现在类中,需要使用 DI 容器而不是直接使用类实例。

继承没有问题,因为可重用代码可以用 FP 而不是 OOP 来处理。 Vue 没有明确地推广它,但使前者更加地道和舒适。

TL;DR:坚持普通对象和 FP,因为这是 Vue 反应性设计的主要情况。

© www.soinside.com 2019 - 2024. All rights reserved.