having a weird issue here. maybe its because i did't understood quite right how getters work.
i try to update a list of users which i fetch from jsonplaceholder. the update of the list should trigger when i search for a user in an input field.
quick gif for visualitation:
this is my component:
<template>
<v-app>
<div class="mt-2 ml-2">
<v-btn
color="info"
x-small
@click="fetchUsers()"
>
Reset All
</v-btn>
</div>
<add-user />
<v-text-field
v-model="search"
class="mt-5 px-3"
label="Search"
required
dense
style="width: 300px"
@input="filteredUsers(search)"
/>
<ul
class="mt-1 px-3"
style="list-style: none"
>
<li
v-for="(user, userIndex) in users"
:key="user.id"
>
<ul
class="pl-0"
style="list-style: none"
>
<li
v-for="(value, key, index) in user"
:key="index"
>
<b>{{ key }}:</b> {{ value }}
</li>
<v-btn
x-small
color="error"
class="my-2"
@click="deleteUser(userIndex)"
>
Delete
</v-btn>
</ul>
<hr>
</li>
</ul>
</v-app>
</template>
<script>
import { mapGetters, mapActions } from 'vuex';
import AddUser from '@/components/AddUser';
export default {
name: 'App',
components: {
AddUser,
},
data: () => ({
search: '',
}),
computed: {
...mapGetters(['userWithId', 'users', 'filteredUsers']),
},
created() {
this.fetchUsers();
},
methods: {
...mapActions(['deleteUser', 'fetchUsers']),
},
};
</script>
and this is my store:
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
users: [],
},
getters: {
users: (state) => {
return state.users
},
userWithId: (state) => (id) => {
return state.users.filter((user) => user.id === id)
},
filteredUsers: (state, getters) => (search) => {
// CONSOLE
console.log(
getters.users.filter((user) =>
user.name.toLowerCase().includes(search.toLowerCase())
)
)
// SHOULD DOM UPDATE
return getters.users.filter((user) =>
user.name.toLowerCase().includes(search.toLowerCase())
)
},
},
mutations: {
loadUsers(state, payload) {
state.users = payload
},
deleteUser(state, id) {
state.users.splice(id, 1)
},
addUser(state, payload) {
state.users.push(payload)
},
deleteAllExceptOne(state, id) {
return state.users.filter((user) => user.id === id)
},
},
actions: {
fetchUsers(context) {
axios
.get('https://jsonplaceholder.typicode.com/users')
.then((res) => {
const users = res.data
users.forEach((user) => {
delete user.address
delete user.company
delete user.phone
delete user.website
})
context.commit('loadUsers', users)
})
.catch((err) => {
console.log(err)
})
},
deleteUser(context, userId) {
axios
.delete(`https://jsonplaceholder.typicode.com/users/${userId}`)
.then(() => {
context.commit('deleteUser', userId)
})
.catch((err) => {
console.log(err)
})
},
addUser(context, user) {
axios
.post('https://jsonplaceholder.typicode.com/users')
.then((res) => {
user.id = res.data.id
context.commit('addUser', user)
})
.catch((err) => {
console.log(err)
})
},
},
modules: {},
})
If I understand correctly, you want to display the filtered user list below the search input, right?
It seems the error is that you're iterating over users
instead of filteredUsers
to create the list.
Perhaps, this would work for you:
<template>
<v-app>
...
<v-text-field
v-model="search"
class="mt-5 px-3"
label="Search"
required
dense
style="width: 300px"
/>
<ul
class="mt-1 px-3"
style="list-style: none"
>
<li
v-for="(user, userIndex) in filteredUsers(search)"
:key="user.id"
>
...
</v-app>
</template>
Another suggestion would be to make filteredUsers
a computed property in your component and remove it from your store. It would look like this:
<template>
<v-app>
...
<v-text-field
v-model="search"
class="mt-5 px-3"
label="Search"
required
dense
style="width: 300px"
/>
<ul
class="mt-1 px-3"
style="list-style: none"
>
<li
v-for="(user, userIndex) in filteredUsers"
:key="user.id"
>
...
</v-app>
</template>
<script>
import { mapGetters, mapActions } from 'vuex';
import AddUser from '@/components/AddUser';
export default {
name: 'App',
components: {
AddUser,
},
data: () => ({
search: '',
}),
computed: {
...mapGetters(['userWithId', 'users']),
filteredUsers () {
return this.users.filter((user) =>
user.name.toLowerCase().includes(this.search.toLowerCase())
)
}
},
created() {
this.fetchUsers();
},
methods: {
...mapActions(['deleteUser', 'fetchUsers']),
},
};
</script>