Connecting Pinia and creating a storage
Connect the extension ui.vue3.pinia
inside your own extension or at php page to start the operation.
Import createPinia
from ui.vue3.pinia
in your extension for Pinia storage to work in your extension:
import {createPinia} from 'ui.vue3.pinia';
import {BitrixVue} from 'ui.vue3';
const store = createPinia();
const application = BitrixVue.createApp({
components: {
Component
},
template: '<Component/>'
});
application.use(store);
application.mount('#application');
Use the namespace BX.Vue3.Pinia
within a page and scripts without transpiling and or feature access (for example, for createPinia
, its BX.Vue3.Pinia.createPinia
).
How to create a storage (module)
import {defineStore} from 'ui.vue3.pinia';
const exampleStore = defineStore('example', {
...
});
State export (state/getters)
You need to use data storage in component template for this component to declare such values in template via calculated properties.
You can avoid writing all structure elements manually: use the helper function mapState (this function can be imported from ui.vue3.pinia
):
computed: {
...mapState(counterStore, ['counter', 'double']),
},
The function allows importing variables in a free format:
computed: {
...mapState(counterStore, {
myOwnName: 'counter',
// you also write function that gets access to storage
triple: store => store.counter * 3,
}),
},
Or you can query the variable in a usual format:
computed: {
counterStore: () => counterStore().counter,
},
Action (actions) export
The same approach is applicable to methods: you need to export functions inside the component using the function mapActions (function can be imported from ui.vue3.pinia
):
methods: {
...mapActions(counterStore, ['increaseCounter', 'decreaseCounter']),
// as in the previous approach with mapState, you can rename parameters
...mapActions(useCounterStore, { decrease: 'decreaseCounter' }),
},
Example
Now lets unify these two actions and launch the application.
Let's overview the action: place element with identifier application
at your html-page:
<div id="application"></div>
Execute the following code in JS extension for associating html, Vue and Vuex (it creates a storage, registers component to handle the extension and launches Vue application):
import { BitrixVue } from 'ui.vue3';
import { createPinia, defineStore, mapState, mapActions } from 'ui.vue3.pinia';
// initialize Pinia
const store = createPinia();
// create a Counter storage: please note, its a unique name for all of page!
const counterStore = defineStore('counter', {
state: () => ({
counter: 0,
changes: 0
}),
getters: {
double()
{
return this.counter * 2;
},
},
actions: {
increaseCounter()
{
this.counter++;
},
decreaseCounter()
{
this.counter--;
}
},
});
// Create a component to work with a state from Pinia
const Component = {
computed: {
counterMessage()
{
return 'Counter: ' + this.counter;
},
doubleCounterMessage()
{
return 'Double counter:' + this.double;
},
...mapState(counterStore, ['counter', 'double']),
},
methods: {
...mapActions(counterStore, ['increaseCounter', 'decreaseCounter']),
},
// language=Vue
template: `
<div>{{counterMessage}}</div>
<div>{{doubleCounterMessage}}</div>
<div>
<button @click="increaseCounter">+</button>
<button @click="decreaseCounter">-</button>
</div>
`
};
// Create an application, connect Pinia and render into the "#application" tag
const Application = BitrixVue.createApp({
components: {
Component
},
template: `
<Component/>
`
});
Application.use(store);
Application.mount('#application');
Important! Upon declaring storages, you need to very carefully choose names inside function defineStore – first parameter must be unique. This can cause issues, when you use the same storage for different Vue applications (for example, when two different widgets that must have identical storage structure, but with different data).