简体   繁体   中英

Vuex getter filteredUsers not reactiv in dom but in console

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:

getter 中没有 dom 更新

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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM