VueJS DOM не обновляется в компоненте - PullRequest
0 голосов
/ 25 сентября 2018

Я просмотрел другие посты "DOM не обновляет", но не смог найти решение.Я пытаюсь создать приложение задачи для начинающих, и приложение уже может загрузить из Firestore, добавить новое и удалить одно.У меня две проблемы, но я бы хотел начать с первой.Когда я добавляю, удаляю данные, DOM не обновляется динамически, хотя соответствующий массив в хранилище Vuex обновляется правильно.Когда я перезагружаю страницу, она также обновляется.

Я добавил код компонента и магазина, надеюсь, я смотрю в нужном месте, но у меня такое ощущение, что я не прав.

Заранее спасибо

Код магазина:

import Vue from 'vue'
import Vuex from 'vuex'
// import firebase from 'firebase'
import router from '@/router'
import db from '@/db'
import firebase from '@/firebase'

Vue.use(Vuex)

export const store = new Vuex.Store({
  state: {
    appTitle: 'My Awesome App',
    addedTask: false,
    loadedTasks: false,
    deletedTasks: false,
    user: null,
    error: null,
    loading: false,
    tasks: [],
    task: {
      title: '',
      description: '',
      tags: [],
      dueTime: '',
      dueDate: '',
      reminderFlag: Boolean,
      quadrant: '',
      userId: '',
      timestamp: ''
    }
  },
  // Mutations (synchronous): change data in the store
  mutations: {
    setUser (state, payload) {
      state.user = payload
      state.task.userId = firebase.auth().currentUser.uid
    },
    setError (state, payload) {
      state.error = payload
    },
    setLoading (state, payload) {
      state.loading = payload
    },
    addedTask (state, payload) {
      state.addedTask = payload
    },
    loadedTasks (state, payload) {
      state.loadedTasks = true
    },
    deletedTask (state, payload) {
      state.deletedTask = payload
    }
  },
  // Actions (asynchronous/synchronous): change data in the store
  actions: {
    autoSignIn ({ commit }, payload) {
      commit('setUser', { email: payload.email })
    },
    userSignUp ({ commit }, payload) {
      commit('setLoading', true)
      firebase.auth().createUserWithEmailAndPassword(payload.email, payload.password)
        .then(firebaseUser => {
          commit('setUser', { email: firebaseUser.user.email })
          commit('setLoading', false)
          router.push('/home')
          commit('setError', null)
        })
        .catch(error => {
          commit('setError', error.message)
          commit('setLoading', false)
        })
    },
    userSignIn ({ commit }, payload) {
      commit('setLoading', true)
      firebase.auth().signInWithEmailAndPassword(payload.email, payload.password)
        .then(firebaseUser => {
          commit('setUser', { email: firebaseUser.user.email })
          commit('setLoading', false)
          commit('setError', null)
          router.push('/home')
        })
        .catch(error => {
          commit('setError', error.message)
          commit('setLoading', false)
        })
    },
    userSignOut ({ commit }) {
      firebase.auth().signOut()
      commit('setUser', null)
      router.push('/')
    },
    addNewTask ({ commit }, payload) {
      commit('addedTask', false)
      db.collection('tasks').add({
        title: payload.title,
        userId: firebase.auth().currentUser.uid,
        createdOn: firebase.firestore.FieldValue.serverTimestamp(),
        description: payload.description,
        dueDateAndTime: new Date(payload.dueDate & ' ' & payload.dueTime),
        reminderFlag: payload.reminderFlag,
        quadrant: payload.quadrant,
        tags: payload.tags
      })
        .then(() => {
          commit('addedTask', true)
          this.state.tasks.push(payload)
          commit('loadedTasks', true)
        })
        .catch(error => {
          commit('setError', error.message)
        })
    },
    getTasks ({ commit }) {
      commit('loadedTasks', false)
      db.collection('tasks').orderBy('createdOn', 'desc').get().then(querySnapshot => {
        querySnapshot.forEach(doc => {
          const data = {
            'taskId': doc.id,
            'title': doc.data().title,
            'quadrant': doc.data().quadrant
          }
          this.state.tasks.push(data)
        })
        commit('loadedTasks', true)
      })
    },
    deleteTask ({ commit }, payload) {
      db.collection('tasks').doc(payload).delete().then(() => {
        this.state.tasks.pop(payload)
        commit('deletedTask', true)
        commit('loadedTasks', true)
      }).catch(function (error) {
        console.error('Error removing document: ', error)
        commit('deletedTask', false)
      })
    }
  },
  // Getters: receive data from the store
  getters: {
    isAuthenticated (state) {
      return state.user !== null && state.user !== undefined
    }
  }
})

Это компонент (Vue app -> Home -> Grid -> Tasklist (this):

<template>

  <v-card>

    <v-card-title primary class="title">{{title}}</v-card-title>

    <v-flex v-if="tasks.length > 0">
      <v-slide-y-transition class="py-0" group tag="v-list">
        <template v-for="(task, i) in tasks" v-if="task.quadrant === Id">
          <v-divider v-if="i !== 0" :key="`${i}-divider`"></v-divider>

          <v-list-tile :key="`${i}-${task.text}`">
            <v-list-tile-action>
              <v-checkbox v-model="task.done" color="info darken-3">
                <div slot="label" :class="task.done && 'grey--text' || 'text--primary'" class="text-xs-right" v-text="task.title +' ('+ task.taskId +')'"></div>
              </v-checkbox>
            </v-list-tile-action>
            <v-spacer></v-spacer>
            <v-scroll-x-transition>
              <v-btn flat icon color="primary" v-show="!deleteConfirmation" @click="deleteConfirmation = !deleteConfirmation">
                <v-icon>delete</v-icon>
              </v-btn>
            </v-scroll-x-transition>

            <v-scroll-x-transition>
              <v-btn flat icon color="green" v-show="deleteConfirmation" @click="deleteConfirmation = !deleteConfirmation">
                <v-icon>cancel</v-icon>
              </v-btn>
            </v-scroll-x-transition>

            <v-scroll-x-transition>
              <v-btn flat icon color="red" v-show="deleteConfirmation" @click="deleteConfirmation = !deleteConfirmation; deleteTask(task.taskId)">
                <v-icon>check_circle</v-icon>
              </v-btn>
            </v-scroll-x-transition>

          </v-list-tile>
        </template>
      </v-slide-y-transition>
    </v-flex>
  </v-card>
</template>

<script>

export default {
  data () {
    return {
      deleteConfirmation: false
    }
  },
  props: ['Id', 'title'],
  computed: {
    tasks () {
      return this.$store.state.tasks
    }
  },
  methods: {
    deleteTask (taskId) {
      console.log(taskId)
      this.$store.dispatch('deleteTask', taskId)
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
    <style scoped>
.container {
  max-width: 1200px;
}
</style>

Ответы [ 2 ]

0 голосов
/ 26 сентября 2018

DOM теперь обновляется, удаляется должным образом.Я немного изменяю структуру компонентов.Теперь это: Vue app -> Home -> Grid -> Tasklist -> TaskListItem.Я все еще сталкиваюсь со следующей проблемой: Добавление элемента обновляет DOM, но когда я добавляю несколько записей, например, с разными заголовками, они записываются в Firestore корректно, но в DOM он показывает их все как идентичные, пока я не выполню полную перезагрузку.

Пожалуйста, найдите код ниже:

Магазин:

import Vue from 'vue'
import Vuex from 'vuex'
// import firebase from 'firebase'
import router from '@/router'
import db from '@/db'
import firebase from '@/firebase'

Vue.use(Vuex)

export const store = new Vuex.Store({
  state: {
    appTitle: 'My Awesome App',
    taskFormVisible: false,
    addedTask: false,
    loadedTasks: false,
    deletedTasks: false,
    user: null,
    error: null,
    loading: false,
    tasks: [],
    task: {
      title: '',
      description: '',
      tags: [],
      dueTime: '',
      dueDate: '',
      reminderFlag: Boolean,
      quadrant: '',
      userId: '',
      timestamp: ''
    }
  },
  // Mutations (synchronous): change data in the store
  mutations: {
    setUser (state, payload) {
      state.user = payload
      state.task.userId = firebase.auth().currentUser.uid
    },
    setError (state, payload) {
      state.error = payload
    },
    setLoading (state, payload) {
      state.loading = payload
    },
    addedTask (state, payload) {
      state.addedTask = payload
    },
    loadedTasks (state, payload) {
      state.loadedTasks = true
    },
    deletedTask (state, payload) {
      state.deletedTask = payload
    },
    DELETE_TASK (state, payload) {
      state.tasks = state.tasks.filter(task => {
        return task.taskId !== payload
      })
    },
    ADD_NEW_TASK (state, payload) {
      // algorithm to remove, e. g. by id
      // console.log(payload)
      state.tasks.push(payload)
      /* state.tasks = state.tasks.filter(e => {
        return e.id !== payload
      }) */
    },
    GET_TASKS (state, payload) {
      state.tasks = payload
    },
    MAKE_TASKFORM_VISIBLE (state, payload) {
      state.taskFormVisible = payload
    }

  },
  // Actions (asynchronous/synchronous): change data in the store
  actions: {
    autoSignIn ({ commit }, payload) {
      commit('setUser', { email: payload.email })
    },
    userSignUp ({ commit }, payload) {
      commit('setLoading', true)
      firebase.auth().createUserWithEmailAndPassword(payload.email, payload.password)
        .then(firebaseUser => {
          commit('setUser', { email: firebaseUser.user.email })
          commit('setLoading', false)
          router.push('/home')
          commit('setError', null)
        })
        .catch(error => {
          commit('setError', error.message)
          commit('setLoading', false)
        })
    },
    userSignIn ({ commit }, payload) {
      commit('setLoading', true)
      firebase.auth().signInWithEmailAndPassword(payload.email, payload.password)
        .then(firebaseUser => {
          commit('setUser', { email: firebaseUser.user.email })
          commit('setLoading', false)
          commit('setError', null)
          router.push('/home')
        })
        .catch(error => {
          commit('setError', error.message)
          commit('setLoading', false)
        })
    },
    userSignOut ({ commit }) {
      firebase.auth().signOut()
      commit('setUser', null)
      router.push('/')
    },
    makeTaskformVisible ({ commit }) {
      if (this.state.taskFormVisible === false) {
        commit('MAKE_TASKFORM_VISIBLE', true)
      } else {
        commit('MAKE_TASKFORM_VISIBLE', false)
      }
    },
    addNewTask ({ commit }, payload) {
      db.collection('tasks').add({
        title: payload.title,
        userId: firebase.auth().currentUser.uid,
        createdOn: firebase.firestore.FieldValue.serverTimestamp(),
        description: payload.description,
        dueDateAndTime: payload.dueTimestamp,
        reminderFlag: payload.reminderFlag,
        quadrant: payload.quadrant,
        tags: payload.tags,
        updatedOn: firebase.firestore.FieldValue.serverTimestamp()
      })
        .then(() => {
          commit('ADD_NEW_TASK', payload)
        })
        .catch(error => {
          commit('setError', error.message)
        })
    },
    getTasks ({ commit }) {
      // commit('loadedTasks', false)
      db.collection('tasks').orderBy('createdOn', 'desc').get().then(querySnapshot => {
        querySnapshot.forEach(doc => {
          const data = {
            'taskId': doc.id,
            'title': doc.data().title,
            'quadrant': doc.data().quadrant
          }
          this.state.tasks.push(data)
        })
        // commit('loadedTasks', true)
        commit('GET_TASKS', this.state.tasks)
      })
    },
    deleteTask ({ commit }, payload) {
      db.collection('tasks').doc(payload).delete().then(() => {
        commit('DELETE_TASK', payload)
      }).catch(function (error) {
        // console.error('Error removing document: ', error)
        commit('setError', error.message)
      })
    }
  },
  // Getters: receive data from the store
  getters: {
    isAuthenticated (state) {
      return state.user !== null && state.user !== undefined
    }
  }
})

TaskList:

<template>

  <ul>
    <li>
      <h4>{{title}}</h4>
    </li>
    <li v-for="task in tasks" :key="task.taskId" v-if="task.quadrant === Id" class="collection-item">
      <task-list-item v-bind:task="task"></task-list-item>
    </li>
  </ul>
</template>

<script>
import TaskListItem from './TaskListItem'

export default {
  components: {
    'task-list-item': TaskListItem
  },
  data () {
    return {

    }
  },
  props: ['Id', 'title'],
  computed: {
    tasks () {
      return this.$store.state.tasks
    }
  },
  methods: {

  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
    <style scoped>

</style>

TaskListItem:

<template>
  <div>{{task.title}} ({{task.taskId}})<v-spacer></v-spacer>
    <v-scroll-x-transition>
      <v-btn flat icon color="primary" v-show="!deleteConfirmation">
        <v-icon>edit</v-icon>
      </v-btn>
    </v-scroll-x-transition>
    <v-scroll-x-transition>
      <v-btn flat icon color="primary" v-show="!deleteConfirmation" @click="deleteConfirmation = !deleteConfirmation">
        <v-icon>delete</v-icon>
      </v-btn>
    </v-scroll-x-transition>

    <v-scroll-x-transition>
      <v-btn flat icon color="green" v-show="deleteConfirmation" @click="deleteConfirmation = !deleteConfirmation">
        <v-icon>cancel</v-icon>
      </v-btn>
    </v-scroll-x-transition>

    <v-scroll-x-transition>
      <v-btn flat icon color="red" v-show="deleteConfirmation" @click="deleteConfirmation = !deleteConfirmation; deleteTask(task.taskId)">
        <v-icon>check_circle</v-icon>
      </v-btn>
    </v-scroll-x-transition>
    </li>
  </div>

</template>

<script>

export default {
  data () {
    return {
      deleteConfirmation: false
    }
  },
  props: ['task'],
  computed: {

  },
  methods: {
    deleteTask (taskId) {
      this.$store.dispatch('deleteTask', taskId)
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
    <style scoped>

</style>
0 голосов
/ 25 сентября 2018

У вас нет мутации, чтобы фактически изменить ваш массив tasks, как, например, this.state.tasks.pop(payload) происходит в действии deleteTask, а не мутации.

Единственный способ действительно изменить состояние вМагазин Vuex - это совершить мутацию.https://vuex.vuejs.org/guide/mutations.html

Это также причина, по которой вы видите правильный результат после перезагрузки: реализация Firestore в порядке и обновляет свои значения.Он покажет обновленный и только что полученный массив tasks после перезагрузки , но состояние Vuex никогда не изменится до перезагрузки , поэтому отображение массива tasks в Vue остается прежним.

Решение этой проблемы довольно простое:

Создайте новую мутацию:

REMOVE_FROM_TASKS (state, payload) {
    // algorithm to remove, e. g. by id
    state.tasks = state.tasks.filter(e => {
        return e.id !== payload;
    });
},

Используйте эту мутацию в своем действии:

deleteTask ({ commit }, payload) {
  db.collection('tasks').doc(payload).delete().then(() => {
    commit('REMOVE_FROM_TASKS', payload)
    commit('deletedTask', true)
    commit('loadedTasks', true)
  }).catch(function (error) {
    console.error('Error removing document: ', error)
    commit('deletedTask', false)
  })
}
...