pinia use state instead of this in actions - vue.js

In Vue3 compisition API,I don't usually use this
But pinia example is:
increment() {
this.counter++
},
Dont want use this in action.Has any suggest?

You can use a function (similar to a component setup()) to define a Store. Then you can declear actions and getters without calling this. Official Doc Link
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
function increment() {
count.value++
}
return { count, increment }
})

Related

Access default state in Pinia

I am trying to migrate from Vuex to Pinia and I couldn't figure out what defaultStateFactory() equivalent is in Pinia.
Here is an mutation from Vuex. I want to convert this to Pinia.
setOperatedAddress(state, payload) {
if (payload) {
Object.assign(state.operatedAddress, payload)
} else {
Object.assign(state.operatedAddress, defaultStateFactory().operatedAddress)
}
}
If no address provided I want operated address to fall back to initial empty state.
You can achieve this simply by defining your state function externally, and use it both in the store definition and inside your actions. Something like this:
const defaultStateFactory = () => {
return {
operatedAddress: 'foo'
}
}
const myStore = defineStore('myStore', {
state: defaultStateFactory,
actions: {
setOperatedAddress(payload) {
this.operatedAddress = payload ?? defaultStateFactory().operatedAddress
}
},
})

Vue 3 composition API with updating refs

I am passing a ref value to a composable function, updateableSetting. This has an initial value, settingA, but can be updated by the user. When updated, us it possible to have useFeature run again and return an updated feature value?
export default defineComponent({
setup() {
const updateableSetting = ref('settingA')
const { feature } = useFeature(updateableSetting.value)
}
})
Sure. Use a computed property
import { ref, defineComponent, computed} from 'vue'
const useFeature = (initialRef) => {
const feature = computed(() => initialRef.value + ' - I am always up to date!')
return {
feature
}
}
export default defineComponent({
setup() {
const updateableSetting = ref('settingA')
//make sure you don't pass .value here - pass the whole ref object instead
const { feature } = useFeature(updateableSetting)
return { feature }
}
})
If you mean "run a function everytime updatedValue changes", you can use
watch(
[updatedValue],
() => {console.log('updatedValue changed! doing some calculations...')}
)
I had same problem when using composables in nuxt 3.
In nuxt 3 new reactive state is available called useState. try useState instead of ref.
for more information see nuxt 3 document: useState nuxt3

Vue 3 with Vuex 4

I'm using Vue 3 with the composition API and trying to understand how I can map my state from Vuex directly so the template can use it and update it on the fly with the v-model.
Does mapState works or something else to solve this issue? Right no I need to get my state by a getter, print it out in the template, and then do a manual commit for each field in my state... In Vue 2 with Vuex, I had this 100% dynamic
To make two-way binding between your input and store state you could use a writable computed property using set/get methods :
setup(){
const store=useStore()
const username=computed({
get:()=>store.getters.getUsername,
set:(newVal)=>store.dispatch('changeUsername',newVal)
})
return {username}
}
template :
<input v-model="username" />
I've solved it!
Helper function:
import { useStore } from 'vuex'
import { computed } from 'vue'
const useMapFields = (namespace, options) => {
const store = useStore()
const object = {}
if (!namespace) {
console.error('Please pass the namespace for your store.')
}
for (let x = 0; x < options.fields.length; x++) {
const field = [options.fields[x]]
object[field] = computed({
get() {
return store.state[namespace][options.base][field]
},
set(value) {
store.commit(options.mutation, { [field]: value })
}
})
}
return object
}
export default useMapFields
And in setup()
const {FIELD1, FIELD2} = useMapFields('MODULE_NAME', {
fields: [
'FIELD1',
etc…
],
base: 'form', // Deep as next level state.form
mutation: 'ModuleName/YOUR_COMMIT'
})
Vuex Mutation:
MUTATION(state, obj) {
const key = Object.keys(obj)[0]
state.form[key] = obj[key]
}

How to access Vuex map helpers with Composition API

I am using Composition API in Vue2. Can you tell me how to access mapState with composition API? I want to watch for state changes as well. Hence I would have to use it within setup function as well (not only in return). Thanks
The Vuex map helpers aren't supported (yet?) in the Vue 2 or Vue 3 composition API, and this proposal for them has been stalled for a while.
You'll have to manually create a computed like in the docs:
const item = computed(() => store.state.item);
A more complete example:
import { computed } from 'vue';
import { useStore } from 'vuex';
export default {
setup() {
const store = useStore();
const item = computed(() => store.state.item);
return {
item
};
}
}
For me the trick was using the vuex-composition-helper npm package.
https://www.npmjs.com/package/vuex-composition-helpers
import { useState, useActions } from 'vuex-composition-helpers';
export default {
props: {
articleId: String
},
setup(props) {
const { fetch } = useActions(['fetch']);
const { article, comments } = useState(['article', 'comments']);
fetch(props.articleId); // dispatch the "fetch" action
return {
// both are computed compositions for to the store
article,
comments
}
}
}

Returning a getters in a computed create a loop

I am calling inside the computed an action from the store to run it and after I am returning a getter, this will create a loop.
The HTML
{{loadedProjects}}
The computed
computed: {
loadedProjects() {
this.$store.dispatch("getProjects");
return this.$store.getters.loadedProjects;
}
}
The store
import Vuex from "vuex";
import axios from "axios";
const createStore = () => {
return new Vuex.Store({
state: {
loadedProjects: []
},
mutations: {
setProjects(state, projects) {
state.loadedProjects = projects
}
},
actions: {
getProjects(vuexContext) {
console.log("hello1")
return axios.get("THE API URL")
.then(res => {
console.log("hello2")
vuexContext.commit("setProjects", res.data);
})
.catch(e => console.log(e));
}
},
getters: {
loadedProjects(state) {
return state.loadedProjects;
}
}
});
};
export default createStore;
I expect to call my action to populate my state and after to return my state to render my data.
What is the point of using the store action that makes an API call inside the computed property ... maybe you want to trigger loadedProjects change ? ....computed property is not asynchronous so either way the return line will be executed before the you get the response... you might try vue-async-computed plugin OR just use the call on the created hook like you have done which is the better way and you don't have to use a computed property you can just {{ $store.getters.loadedProjects }} on your template
Computed properties should not have side effects (e.g. calling a store action, changing data, and so on). Otherwise it can happen that the triggered side effect could lead to a re-rendering of the component and possible re-fetching of the computed property. Thus, an infinite loop
I changed the code like that:
created: function () {
this.$store.dispatch("getProjects")
},
computed: {
loadedProjects() {
return this.$store.getters.loadedProjects
}
}
It is working now but I would like to know but I have that problem working inside the computed and also I wonder if it's the best solution. Any help????