Skip to content

Migration from Vuex in Shopware to Pinia

Migration from Vuex in Shopware to Pinia ​

With the release of Shopware 6.7, we will replace Vuex with Pinia as the state management library for the administration.

Why Pinia? ​

Migrating to Pinia simplifies state management with an intuitive API, eliminates the need for mutations, provides better TypeScript support, and enables seamless integration with Vue 3 Composition API. It’s lightweight, modular, and offers modern features like devtools support, making it a more efficient alternative to Vuex.

Migration Guide ​

To migrate a Vuex store to Pinia, you need to update the store definition and how you access it in components.

  • First, register it with Shopware.Store.register and define the store with state, getters, and actions properties:

Before (Vuex):

javascript
export default {
    namespaced: true,

    state: {
      // Initial state
 ...
 },
    mutations: {
 ...
 },
    getters: {
 ...
 },
    actions: {
 ...
 },
}

After (Pinia):

javascript
const store = Shopware.Store.register('<storeName>', {
    state: () => ({
        // Initial state
 ...
 }),
    getters: {
 ...
 },
    actions: {
 ...
 },
});
export default store;
  • You can also register the store with an id property in the definition object, for example:
javascript
const store = Shopware.Store.register({
    id: '<storeName>',
    state: () => ({
        // Initial state
 }),
    getters: {
       // ...
 },
    actions: {
       // ...
 },
});
  • If you register a store that already exists, it will be overwritten. You can also unregister a store:
javascript
Shopware.Store.unregister('<storeName>');
  • To register a store from a component or index file, simply import the store file.

Before (Vuex):

javascript
import productsStore from './state/products.state';

Shopware.State.registerModule('product', productsStore);

After (Pinia):

javascript
import './state/products.state';

Key Changes ​

State ​

In Pinia, state must be a function that returns the initial state rather than a static object.

javascript
state: () => ({
    productName: '',
})

Mutations ​

Vuex mutations are no longer needed in Pinia, since you can modify the state directly in actions or compute it dynamically.

javascript
actions: {
    updateProductName(newName) {
        this.productName = newName; // Directly update state
 },
},

Getters ​

  • There cannot be getters with the same name as a property in the state, as both are exposed at the same level in the store.
  • Getters should be used to compute and return information based on state, without modifying it.

TypeScript ​

We recommend migrating JavaScript stores to TypeScript for stricter typing, better autocompletion, and fewer errors during development.

typescript
const store = Shopware.Store.register({
  id: 'myStore',
 ...
});

export type StoreType = ReturnType<typeof store>;

Then, you can use this type to extend PiniaRootState:

typescript
import type { StoreType } from './store/myStore';

declare global {
    interface PiniaRootState {
        myStore: StoreType;
 }
}

Composables as a Store ​

With Pinia, you can use reactive properties in a store and define them as composable. Keep in mind that Pinia will track only variables and functions returned from the store in devtools.

typescript
const store = Shopware.Store.register('<storeName>', function() {
  const count = ref(0);

  const doubled = computed(() => count.value * 2);

  function increment() {
    count.value++;
 }

  function decrement() {
    count.value--;
 }

  return { count, doubled, increment, decrement };
});

You can also use a composable function defined outside the store. This allows you to encapsulate and reuse logic across different stores or components, promoting better code organization and modularity:

typescript
// composables/myComposable.ts
export function useMyComposable() {
  const count = ref(0);

  const doubled = computed(() => count.value * 2);

  function increment() {
    count.value++;
 }

  function decrement() {
    count.value--;
 }

  return { count, doubled, increment, decrement };
}
typescript
// store/myStore.ts
import { useMyComposable } from '../composables/myComposable';

const store = Shopware.Store.register('myStore', useMyComposable);

Accessing the Store ​

To access the store in Vuex, you would typically do:

javascript
Shopware.State.get('<storeName>');

When migrating to Pinia, it changes to:

javascript
Shopware.Store.get('<storeName>');

Testing ​

To test your store, just import it so it's registered. You can use $reset() to reset the store before each test:

javascript
import './store/my.store';

describe('my store', () => {
  const store = Shopware.Store.get('myStore');

  beforeEach(() => {
    store.$reset();
 });

  it('has initial state', () => {
    expect(store.count).toBe(0);
 });
});

When testing components that use Pinia stores, register Pinia as a plugin and reset it before each test:

javascript
import { createPinia, setActivePinia } from 'pinia';

const pinia = createPinia();

describe('my component', () => {
  beforeEach(() => {
    setActivePinia(pinia);
 });

  it('is a component', async () => {
    const wrapper = mount(await wrapTestComponent('myComponent', { sync: true }), {
      global: {
        plugins: [pinia],
        stubs: {
          // ...
 },
 },
 });

    expect(wrapper.exists()).toBe(true);
 });
});
Was this page helpful?
UnsatisfiedSatisfied
Be the first to vote!
0.0 / 5  (0 votes)