Maison  >  Questions et réponses  >  le corps du texte

Pourquoi Pinia/Vuex est-il préféré à l'approche classique avec classes de service ?

Ananas/Vache

Pinia/Vuex ainsi que Redux sont conçus pour être une « source unique de vérité » dans laquelle vous pouvez disposer d'un ou plusieurs magasins pour contenir des données d'application pouvant être obtenues de n'importe où.

La boutique Pinia ressemble à ceci :

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

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

    return {data, getList};
});

peut alors être utilisé comme :

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

Nous pouvons créer plusieurs magasins :

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

Les magasins peuvent se référencer les uns les autres :

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

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

//Et cetera

Enfin, Pinia/Vuex sont des outils qui offrent la possibilité de récupérer et de manipuler des données stockées dans l'état.

Manager/Classe de service

Mais il existe une autre approche plus mature : les cours manager/service.

L'exemple précédent peut être réécrit comme :

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

Tout cela peut être facilement saisi dans TypeScript sans avoir besoin de wrappers supplémentaires, ref() etc.

Discuter

D'après ce que je peux dire, Pinia ressemble à « réinventer la roue » : écrire la même fonctionnalité de manière maladroite.

De plus, il ne fournit pas d'injection de dépendances : vous ne pouvez pas initialiser les magasins dans la configuration et injecter exactement un magasin dans un autre, vous devez passer useProductsStore() et ainsi de suite.

L'héritage ou tout autre élément POO n'est pas non plus possible.

Pinia favorise même les dépendances circulaires, ce qui entraîne un code spaghetti avec une mauvaise maintenabilité

Alors, après tout, pourquoi préférer Pinia/Vuex à l'approche POO propre et éprouvée avec des classes de manager ? J'ai passé des dizaines d'heures à écrire un projet de didacticiel de ma propre invention en utilisant Pinia comme "prochaine gestion d'état Vue recommandée", et maintenant je suis tenté de tout réécrire dans des classes de gestionnaire parce que je trouve Pinia maladroit et riche. Je viens de me rappeler qu'il y a quelques années, j'écrivais un autre projet de test - en utilisant Vue2 - et à cette époque j'utilisais la classe manager - et tout s'est bien passé. Ai-je oublié quelque chose ? Y aura-t-il un problème si j'abandonne Pinia ?

P粉358281574P粉358281574283 Il y a quelques jours465

répondre à tous(1)je répondrai

  • P粉781235689

    P粉7812356892024-01-11 16:00:31

    Les classes sont des citoyens de seconde zone dans la réactivité de Vue, et il y a quelques pièges. Le fait qu'ils ne puissent pas être liés dans le constructeur this,这将导致使用非反应式类实例反应式代理。他们无法有效地使用引用,因为这些引用是在记录但异常的方式。他们无法使用 get/set 访问器来计算引用。这些问题需要显式使用 Vue 反应性 API 以奇怪的方式编写类,或者以受限制的方式设计类,因此 reactive(new MyClass) n'empêche pas celui-ci de fonctionner correctement.

    Les classes n'ont pas de fonctionnalités dont disposent les magasins, telles qu'une prise en charge étendue des outils de développement Vue, des systèmes de plug-ins, etc.

    Les classes ne sont pas non plus sérialisables en JavaScript, donc la sauvegarde et la restauration de l'état nécessitent une logique personnalisée plutôt qu'une simple (dé)sérialisation JSON comme dans le plugin de persistance de stockage.

    L'injection de dépendances n'est pas propre aux cours et peut être réalisée de manière adaptée, par exemple pour le magasin Pinia :

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

    Dans de nombreux cas, il est préférable de gérer le stockage des composables par Pinia plutôt que de stocker les instances, car cela résout les dépendances circulaires qui peuvent devenir un problème si les composables sont appelés prématurément. Le même problème peut survenir avec les classes et nécessite l'utilisation d'un conteneur DI au lieu d'utiliser directement des instances de classe.

    L'héritage ne pose aucun problème car le code réutilisable peut être géré avec FP au lieu de la POO. Vue n'en fait pas explicitement la promotion, mais rend le premier plus idiomatique et plus confortable à utiliser.

    TL;DR : restez fidèle aux objets simples et au FP car c'est le cas principal de la conception réactive de Vue.

    répondre
    0
  • Annulerrépondre