Vue getters dont work - only get content at string of function - vue.js

Getters in Vuex dont work. Why I dont have table of objects? I get function in string...
export const state = () => {
return{
users: [
{name: 'Test', surname: 'Testowski'},
{name: 'Michał', surname: 'Topór'},
{name: 'Jan', surname: 'Janowski'},
{name: 'Ewa', surname: 'Jakas'},
{name: 'Tessst2', surname: 'Testowska'}
]
}
}
export const getters = {
getUsers: (state) => state.users
}
export default {
name: "StatusPanel",
computed:{
users(){
const tmp = this.$store.users.getters.getUsers;
console.info(tmp);
return tmp
}
}
}
What is wrong, why console.log is:
"ƒ getUsers(state) {
return state.users; }"
I tried add "()" in the end to maybe execute this function but then:
"Cannot read property 'users' of undefined""
What I do wrong?

Per the documentation here: https://vuex.vuejs.org/guide/getters.html
Your store should be defined as:
const store = new Vuex.Store({
state: {
users: [...]
},
getters: {
users: state => state.users
}
})
Then you should be able to access this.$store.getters.getUsers. I believe the problem is that you're not using new Vuex.Store({...}).

Related

Vuex store: When i try to add new object to array cause error as "Duplicate keys detected: 'test1'. This may cause an update error. "

When I try to add an object to an array, it updates existing objects of the array and displays the error as: "Duplicate keys detected: 'test'. This may cause an update error". Can you please help me in resolving the issue.
Below is my code:
index.vue
methods: {
...mapActions({
saveItem: 'admin/saveItem'
}),
createItem() {
const saveItemFunc = this.saveItem
saveItemFunc({ "Test item", "category" })
},
}
actions.js
saveItem({ commit, dispatch, state }, payload) {
commit('addItemToBeSaved', payload)
}
mutations.js
addItemToBeSaved: (state, { name, type } ) => {
state.items.push(state.item)
state.items[state.count].name = name
state.items[state.count].type = type
state.count = state.count + 1
}
State.js
export default function() {
return {
items: [],
count: 0,
item: {
name: '',
type: ''
}
}
}

firestoreConnect: firestore.ordered is undefined

The layout of my data in Firestore:
User documents contain an array of id references to chat documents.
Ex:
collections
/users
'CQATa3f3d2XmBskmmt8hmCJhzcJ2'
name: '...'
email: '...'
chats: ["RuUKEwsGtR9QylicdgJW", "JlzcIfkZ1KzeXClhJvOE"]
/chats
...
For the current user, I want to get the chat object associated with each element in its chat array. This data should go to firestore.ordered so I can supply it to a FlatList, but firestore.ordered.chats is always undefined, even though firestore.data.chats has the correct data.
I'm not sure if this is an issue having to do with the order in which I call connect and firestoreConnect or how I am using populates, or something else.
... Component ...
const populates = [
{ child: 'chats', root: 'chats' }
]
const mapStateToProps = (state, props) => {
return {
auth: state.firebase.auth,
user: populate(state.firestore, 'users', populates),
chats: state.firestore.ordered.chats,
}
}
// ---- TEST ----
export default compose(
connect(mapStateToProps, mapDispatchToProps),
firestoreConnect((props) => {
return [ { collection: 'users', doc: props.auth.uid, populates } ]
}),
)(Main)
Result of logging state inside of mapStateToProps:
I ended up just getting the array of chats from the result of the populate call.
const populates = [
{ child: 'chats', root: 'chats', keyProp: 'subjectName', queryParams: ['orderByKey'] }
]
const mapStateToProps = (state, props) => {
const populatedUser = populate(state.firestore, 'users', populates)
let chats = null
if(populatedUser){
chats = Object.values(populatedUser[state.firebase.auth.uid].chats)
}
return {
auth: state.firebase.auth,
user: populatedUser,
chats: chats
}
}
// ---- TEST ----
export default compose(
connect(mapStateToProps, mapDispatchToProps),
firestoreConnect((props) => {
return [ { collection: 'users', doc: props.auth.uid, populates } ]
}),
)(Main)

Vue - deep copy with vuex doesn't work in vuejs

there
when I use Vue + Vuex in my project, I found an issue,
my code:
store:
const state = {
createInfo: {
id: 0,
// group_id: rootState.home.currentGroup,
content: '',
image_info: [],
video_info: [],
lat: '',
lng: '',
type: 1
},
list: [],
canLoad: true
}
function of mutations:
setPublishInfoImages(state, {key, value}) {
if (key === 'push') {
state.createInfo.image_info.push(value)
} else {
state.createInfo.image_info.splice(key, 1)
}
},
on page
first way:
let sourceTopic = Object.assign({}, {
image_info: [],
video_info: [],
content: '',
type: 1
}, JSON.parse(JSON.stringify(this.$store.getters['topic/signTopic'](topic))))
second way:
let sourceTopic = Object.assign({}, {
image_info: [],
video_info: [],
content: '',
type: 1
}, Object.assign({}, this.$store.getters['topic/signTopic'](topic))
I want deep copy a source Object which in state's list array from state use getter
const getters = {
/** get sign topic */
signTopic: (state) => (id) => {
return state.list.data.find((topic) => topic.id === id) || {}
}
}
yes, I got the Object from state,
but when I update the state (uploadimage, and push image-url into state),
first way, there is only one image-url in source images array forever,
second way, when I cannel editing source object, uploaded image-urls will be stored in source object
how can i resolve this issue?

Vuex - Passing a state's object into another state's object

In Vuex I'm trying to pass a state's object (a string in this case), into another state's object, but it is returning undefined.
state: {
notifications: [
{ key: "success",
notification: "Awesome " + this.theName + "! Success.",
redirectPath: "/home"
},
{ key: "error",
notification: "Oh no " + this.theName + "... Error.",
redirectPath: "/error"
}
],
theName: 'Ricky Bobby' // this would normally come from a mutation method - see below
}
The example above the theName is hard-coded just for testing but its value is coming from a mutation method. I know it is coming in into the store's state, because I am able to console log it. But the string interpolation inside the notifications object is not working. How can I pass that incoming value into the notifications.notification value?
I don't know if this helps, but here is the mutation example:
mutations: {
loginSuccess(state, payload){
state.theName = payload.uName;
}
}
There're two issues with your code. Firstly, this doesn't work the way you're trying to make it to do. In your question this inside each notification doesn't refer to the state or any other part of your code. Its value is the global window object or undefined, depends on whether you are in strict mode:
const object = {
propName: this,
};
console.log(object.propName);
Secondly, you code is asynchronous, so theName would change from time to time, but you never actually redefine message strings in your notifications. And they won't be 'recalculated' by itself:
let surname = 'Whyte';
const object = {
fullName: 'Pepe ' + surname,
};
console.log(object.fullName);
setTimeout(() => {
surname = 'White';
console.log(object.fullName);
console.log('the value of \'surname\' variable is ' + surname + ' though.');
}, 2000);
What you can do in your case is to define notification as a function:
notification(name) { return "Awesome " + name + "! Success."}
Then write a getter for notifications and pass a name to the function.
Or as an alternative you can refer to the object itself inside the function. Like this:
let surname = 'Whyte';
const object = {
person: {
firstName: 'Pepe ',
fullName: () => {
return object.person.firstName + ' ' + surname;
},
}
};
console.log(object.person.fullName());
setTimeout(() => {
object.person.firstName = 'Keke';
console.log(object.person.fullName());
}, 1000);
UPD: I've made another example for you. It's hard to tell how exactly you are going to call this notifications, but here are two options you can access them the way you want (jsfiddle):
const store = new Vuex.Store({
state: {
theName: 'Ricky Bobby',
// accessing `theName` prop inside state (probably won't be possible in the real project or very inconvinient due to modularity)
successNotificationInState: () => `Awesome ${store.state.theName}! Success.`,
},
// accessing the same prop with getter
getters: {
successNotification: (state) => `Awesome ${state.theName}! Success.`,
},
mutations: {
loginSuccess(state, payload) {
state.theName = payload.uName;
},
},
actions: { // let's emulate a login
login({
commit
}) {
return new Promise(fullfil => {
setTimeout(function() {
console.log('logging in')
const response = {
uName: 'Keke',
email: 'keke#gmail.com',
}
fullfil(response);
commit('loginSuccess', response);
}, 2000);
});
},
},
});
const app = new Vue({
el: "#app",
store,
data: {
msgGetter: '',
msgState: '',
},
computed: {},
methods: {
login() {
this.$store.dispatch('login').then((response) => {
console.log(response);
console.log(this.$store);
this.msgGetter = this.$store.getters.successNotification;
this.msgState = this.$store.state.successNotificationInState();
});
},
},
mounted() {
this.login();
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.0.1/vuex.js"></script>
<script src="https://unpkg.com/vue"></script>
<div id="app">
<p>Message from state: {{msgState}}</p>
<p>Message from getter: {{msgGetter}}</p>
</div>

Eslint state already declared [Vuex]

I am running ESLint and I am currently running into the following ESLint error:
error 'state' is already declared in the upper scope no-shadow
const state = {
date: '',
show: false
};
const getters = {
date: state => state.date,
show: state => state.show
};
const mutations = {
updateDate(state, payload) {
state.date = payload.date;
},
showDatePicker(state) {
state.show = true;
}
};
export default {
state,
getters,
mutations
};
What would be the best way to fix this?
The best way to fix would be to read the docs about the eslint "no-shadow" rule.
From this documentation, the best solution would probably be to include an exception for this one variable with the "allow" option.
You can add this with a comment to the js file to keep the exeption local:
/* eslint no-shadow: ["error", { "allow": ["state"] }]*/
The best solution is #Linus Borg's answer.
If you are looking for an alternative, you can declare the state constant below the rest. This will prevent variable shadowing because state will not be declared in the outer-scope yet.
Example:
const getters = {
date: state => state.date,
show: state => state.show
};
const mutations = {
updateDate(state, payload) {
state.date = payload.date;
},
showDatePicker(state) {
state.show = true;
}
};
const state = {
date: '',
show: false
};
export default {
state,
getters,
mutations
};
If it's not too late
const data = {
date: '',
show: false
};
const getters = {
date: state => state.date,
show: state => state.show
};
const mutations = {
updateDate(state, payload) {
state.date = payload.date;
},
showDatePicker(state) {
state.show = true;
}
};
export default {
state: data,
getters,
mutations
};
basically you define your store data as data, and you export it as state state: data
Had the same issue as I was using an airbnb eslint config which is incompatible with vuex.
This worked for me, after restarting dev environment.
I created a new .eslintrc.js file in my store folder and added them there
"no-shadow": ["error", { "allow": ["state"] }],
"no-param-reassign": [
"error",
{
"props": true,
"ignorePropertyModificationsFor": [ // All properties except state are in the ignorePropertyModificationsFor array by default.
"state",
"acc",
"e",
"ctx",
"req",
"request",
"res",
"response",
"$scope"
]
}
],
Based on #allochi's answer, this is what I had to do to make it work With Vue 3 which uses Vuex 4 which prefers returning a function for state:
// store.js
const data = {
// ...
};
const getters = {
// ...
};
const mutations = {
// ...
};
const actions = {
// ...
};
export default {
state() { return data; },
getters,
mutations,
actions
};
If you need to import particular functions from outside, you will have to do it like this:
import mystore from './mystore';
const Store = createStore({
state: mystore.state,
getters: mystore.getters,
mutations: mystore.mutations,
actions: mystore.actions
});
I would only recommend this though if you really can't use /* eslint no-shadow: ["error", { "allow": ["state"] }]*/