【问题标题】:Vue.js: Child Component mutates state, parent displays property as undefinedVue.js:子组件改变状态,父组件显示属性未定义
【发布时间】:2021-06-27 15:13:09
【问题描述】:

我有一个列出所有任务的父组件:

<template>
  <div class="tasks-wrapper">
    <div class="tasks-header">
      <h4>{{ $t('client.taskListingTitle') }}</h4>
      <b-button variant="custom" @click="showAddTaskModal">{{ $t('client.addTask') }}</b-button>
    </div>
      <b-table
        striped
        hover
        :items="tasks"
        :fields="fields"
        show-empty
        :empty-text="$t('common.noResultsFound')">
      </b-table>
    <AddTaskModal />
  </div>
</template>

<script>
import { mapActions, mapGetters } from 'vuex'
import AddTaskModal from '@/components/modals/AddTaskModal'
import moment from 'moment'

export default {
  name: 'TaskListing',
  components: {
    AddTaskModal
  },
  data () {
    return {
      tasks: [],
      fields: [
        { key: 'createdOn', label: this.$t('tasks.tableFields.date'), formatter: 'formatDate' },
        { key: 'domain', label: this.$t('tasks.tableFields.task') },
        { key: 'comment', label: this.$t('tasks.tableFields.comment') },
        { key: 'status', label: this.$t('tasks.tableFields.status') }
      ]
    }
  },
  computed: {
    ...mapGetters('users', ['user'])
  },
  methods: {
    ...mapActions('tasks', ['fetchTasks']),
    ...mapActions('users', ['fetchUserById']),
    formatDate: function (date) {
      return moment.utc(date).local().format('DD.MM.YYYY HH:mm')
    },
    showAddTaskModal () {
      this.$bvModal.show('addTaskModal')
    }
  },
  async mounted () {
    const currUserId = this.$router.history.current.params.id
    if (this.user || this.user.userId !== currUserId) {
      await this.fetchUserById(currUserId)
    }
    if (this.user.clientNumber !== null) {
      const filters = { clientReferenceNumber: { value: this.user.clientNumber } }
      this.tasks = await this.fetchTasks({ filters })
    }
  }
}
</script>

在这个组件内部有一个添加任务模式的子组件。

<template>
  <b-modal
    id="addTaskModal"
    :title="$t('modals.addTask.title')"
    hide-footer
    @show="resetModal"
    @hidden="resetModal"
  >
    <form ref="form" @submit.stop.prevent="handleSubmit">
      <b-form-group
        :invalid-feedback="$t('modals.requiredFields')">
        <b-form-select
          id="task-type-select"
          :options="taskTypesOptions"
          :state="taskTypeState"
          v-model="taskType"
          required
        ></b-form-select>
        <b-form-textarea
          id="add-task-input"
          :placeholder="$t('modals.enterComment')"
          rows="3"
          max-rows="6"
          v-model="comment"
          :state="commentState"
          required />
      </b-form-group>
      <b-button-group class="float-right">
        <b-button variant="danger" @click="$bvModal.hide('addTaskModal')">{{ $t('common.cancel') }}</b-button>
        <b-button @click="addTask">{{ $t('modals.addTask.sendMail') }}</b-button>
      </b-button-group>
    </form>
  </b-modal>
</template>

<script>
import { mapActions, mapGetters } from 'vuex'

export default {
  name: 'AddTaskModal',
  data () {
    return {
      comment: '',
      commentState: null,
      taskTypesOptions: [
        { value: null, text: this.$t('modals.addTask.taskType') },
        { value: 'OnBoarding', text: 'Onboarding' },
        { value: 'Accounts', text: 'Accounts' },
        { value: 'TopUp', text: 'Topup' },
        { value: 'Overdraft', text: 'Overdraft' },
        { value: 'Aml', text: 'Aml' },
        { value: 'Transfers', text: 'Transfers' },
        { value: 'Consultation', text: 'Consultation' },
        { value: 'TechnicalSupport', text: 'TechnicalSupport' },
        { value: 'UnblockPin', text: 'UnblockPin' },
        { value: 'Other', text: 'Other' }
      ],
      taskType: null,
      taskTypeState: null
    }
  },
  computed: {
    ...mapGetters('users', ['user']),
    ...mapGetters('tasks', ['tasks'])
  },
  methods: {
    ...mapActions('tasks', ['addNewTask', 'fetchTasks']),
    ...mapActions('users', ['fetchUserById']),
    async addTask (bvModalEvt) {
      bvModalEvt.preventDefault()
      if (!this.checkFormValidity()) { return }
      const currUserId = this.$router.history.current.params.id
      if (this.user || this.user.userId !== currUserId) {
        await this.fetchUserById(currUserId)
      }
      const data = {
        clientPhone: this.user.phoneNumber,
        comment: this.comment,
        clientReferenceNumber: this.user.clientNumber,
        domain: this.taskType
      }
      await this.addNewTask(data)
      if (this.user.clientNumber !== null) {
        const filters = { clientReferenceNumber: { value: this.user.clientNumber } }
        this.tasks = await this.fetchTasks({ filters })
        // this.tasks may be useless here
      }
      console.log(this.tasks)
      this.$nextTick(() => { this.$bvModal.hide('addTaskModal') })
    },
    checkFormValidity () {
      const valid = this.$refs.form.checkValidity()
      this.commentState = valid
      this.taskTypeState = valid
      return valid
    },
    resetModal () {
      this.comment = ''
      this.commentState = null
      this.taskTypeState = null
    }
  }
}
</script>

当我添加一个任务时,我调用 getalltasks 来改变存储,以便添加所有任务。然后我想渲染它们。它们已呈现,但最后一个任务上的 createdOn 属性是 InvalidDate ,当我在控制台记录时它是未定义的。

我需要在模态中再次调用 gettasks 的原因是添加任务的响应没有返回属性 createdOn。我不想在前端设置,我想从数据库中获取。

我登录了商店,所有的任务都添加到了商店中。

为什么我的父组件没有渲染这个特定的 createdOn 属性?

如果我刷新页面,一切都会正常显示。

【问题讨论】:

    标签: vue.js components vuex parent


    【解决方案1】:

    如果您将任何内容添加到 v-for 显示的项目列表中,则必须设置唯一键。根据您的解释,我假设您的键是索引,当您添加新项目时,您会弄乱当前索引。键必须是唯一且不可更改的。您需要做的是为每个元素创建一个唯一的 id。

    {
      id: Math.floor(Math.random() * 10000000)
    }
    

    当你创建一个新任务时,使用相同的代码生成一个新的id,并使用id作为key。如果这没有帮助,请分享您的 d-table 和相关的 vuex 代码。

    【讨论】:

    • 我看不出这与此有什么关系。添加了元素,但日期只是搞砸了。它与 id 无关。 ID 是来自数据库的随机 guid。
    猜你喜欢
    • 2016-12-23
    • 2017-07-10
    • 2020-08-06
    • 1970-01-01
    • 2021-06-08
    • 2021-08-29
    • 1970-01-01
    • 2020-12-30
    • 2019-09-21
    相关资源
    最近更新 更多