Vue.js:子组件改变状态,父组件显示属性未定义
Posted
技术标签:
【中文标题】Vue.js:子组件改变状态,父组件显示属性未定义【英文标题】:Vue.js: Child Component mutates state, parent displays property as undefined 【发布时间】: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 属性?
如果我刷新页面,一切都会正常显示。
【问题讨论】:
【参考方案1】:如果您将任何内容添加到 v-for 显示的项目列表中,则必须设置唯一键。根据您的解释,我假设您的键是索引,当您添加新项目时,您会弄乱当前索引。键必须是唯一且不可更改的。您需要做的是为每个元素创建一个唯一的 id。
id: Math.floor(Math.random() * 10000000)
当你创建一个新任务时,使用相同的代码生成一个新的id,并使用id作为key。如果这没有帮助,请分享您的 d-table 和相关的 vuex 代码。
【讨论】:
我看不出这与此有什么关系。添加了元素,但日期只是搞砸了。它与 id 无关。 ID 是来自数据库的随机 guid。以上是关于Vue.js:子组件改变状态,父组件显示属性未定义的主要内容,如果未能解决你的问题,请参考以下文章