英文:
Vue 3 Component losing reactivity
问题
我已经学习了Vue 3大约一个月,取得了相当大的进展,但无论我尝试了什么,都无法修复这个问题。我知道我失去了响应性,但我无法弄清楚如何做,这让我感到非常烦恼。我正在使用Composition API和带有简单Pinia存储的脚本设置。我在这里创建了一个GitHub存储库:https://github.com/thammer67/vue3-reactivity-problem
我有一个视图(ProjectsView.vue),其中包含循环遍历Pinia存储数组的项目元素,使用v-for并将数组对象作为prop传递。ProjectsView.vue使用一个隐藏的表单组件(ProjectForm.vue),我用它来添加新项目。循环中的每个项目都是另一个组件(ProjectItem.vue),具有指向加载ProjectDetail.vue的路由的点击处理程序。ProjectDetail.vue有一个点击处理程序,也使用ProjectForm.vue来编辑项目。
一切都运作良好。我可以添加新项目,编辑项目,但当我编辑一个项目时,Pinia存储会更新(我可以在Vue Dev工具中看到),但UI不会更新,直到我返回到项目列表。我需要在保存后更新ProjectDetail.vue中的值。以下是相关文件。
ProjectDetail.vue:
<script setup>
import { useProjectStore } from '../stores/ProjectStore'
import { useRoute } from 'vue-router'
import { ref } from 'vue'
import ProjectForm from '@/components/Form/ProjectForm.vue'
const projectStore = useProjectStore()
const route = useRoute()
const id = route.params.id
const project = projectStore.getProjectById(id)
const showEditProject = ref(false)
const editing = ref(false)
const editProject = (id) => {
editing.value = id
showEditProject.value = true
}
</script>
<template>
<div class="main">
<div v-if="project" :project="project">
<h2>Project Details</h2>
<div>
<div class="project-name">{{ project.project }}</div>
</div>
<div style="margin-top: 1em">
<button type="button" @click="editProject(project.id)">Edit</button>
</div>
<ProjectForm
@hideForm="showEditProject=false"
:project="project"
:editing="editing"
:showAddEntry="showEditProject" />
</div>
</div>
</template>
ProjectForm.vue:
<script setup>
import { ref, toRef, reactive } from "vue"
import { useProjectStore } from '@/stores/ProjectStore.js'
import Input from './Input.vue'
const projectStore = useProjectStore()
const showAddType = ref(false)
//Capture 'showAddEntry' prop from parent component
const props = defineProps(['showAddEntry', 'editing', 'project'])
//Copy prop values for the form
const projName = toRef(props.project.project)
const projId = toRef(props.project.id)
//new/edited values are stored on this reactive object
const formState = reactive({
invalid: false,
errMsg: ""
})
const saveProject = () => {
formState.invalid = false
if (projId.value) {
console.log(`Update existing project ${projId.value}`)
projectStore.updateProject({
id: projId.value,
project: projName.value
})
.then(() => {
console.log("save was successful!")
showAddType.value = false
formState.invalid = false
formState.errMsg = ""
emit('hideForm')
})
.catch(err => console.log("Error: ", err))
} else {
console.log(`Create new project`)
//New Project
projectStore.createProject({
project: projName.value,
})
.then(() => {
showAddType.value = false
formState.invalid = false
formState.errMsg = ""
emit('hideForm')
})
}
}
const hideForm = () => {
formState.invalid = false
showAddType.value = false
emit('hideForm')
}
//Define emit event up to the parent that hides the form
const emit = defineEmits(['hideForm'])
</script>
<template>
<div class="addform" :class="{ show: props.showAddEntry }">
<h1 v-if="editing" class="title">Edit Project</h1>
<h1 v-else class="title">Add New Project</h1>
<div class="input-wrap" :class="{ 'input-err': formState.invalid }">
<Input
@input="projName = $event.target.value"
type="text"
placeholder="Enter project name"
:value="projName"
/>
<div class="entry-submit">
<button v-if="editing" @click="saveProject">Save</button>
<button v-else @click="saveProject">Create Project</button>
<button @click="hideForm">Cancel</button>
</div>
</div>
<p v-show="formState.invalid" class="err-msg">{{ formState.errMsg }}</p>
</div>
</template>
这些是您提供的代码的翻译。如果您需要更多帮助或有其他问题,请随时提出。
英文:
I've been learning Vue 3 for the past month or so and have gotten quite far but I can't fix this no matter what I've tried. I know I'm losing reactivity but I can't figure out how and it's driving me nuts. I am using the Composition API and script setup with a simple Pinia store. I created a github repo for it here: https://github.com/thammer67/vue3-reactivity-problem
I have a view (ProjectsView.vue) of project elements that loops through a pinia store array of projects using v-for and passing the array object as a prop. ProjectsView.vue uses a hidden form component (ProjectForm.vue) that I use for adding new projects. Each project in the loop is another component (ProjectItem.vue) with a click handler to a route that loads ProjectDetail.vue. ProjectDetail.vue has a click handler that also uses ProjectForm.vue for editing the item.
Everything works great. I can add new projects, edit projects but when I edit a project the pinia store updates (I can see this in the Vue Dev tools) but the UI doesn't update untill I go back to the project list. I need to update the value in ProjectDetail.vue after saving. Here are the pertinent files.
ProjectDetail.vue:
<script setup>
import { useProjectStore } from '../stores/ProjectStore'
import { useRoute } from 'vue-router'
import { ref } from 'vue'
import ProjectForm from '@/components/Form/ProjectForm.vue'
const projectStore = useProjectStore()
const route = useRoute()
const id = route.params.id
const project = projectStore.getProjectById(id)
const showEditProject = ref(false)
const editing = ref(false)
const editProject = (id)=> {
editing.value = id
showEditProject.value = true
}
</script>
<template>
<div class="main">
<div v-if="project" :project="project">
<h2>Project Details</h2>
<div>
<div class="project-name">{{ project.project }}</div>
</div>
<div style="margin-top: 1em">
<button type="button" @click="editProject(project.id)">Edit</button>
</div>
<ProjectForm
@hideForm="showEditProject=false"
:project="project"
:editing="editing"
:showAddEntry="showEditProject" />
</div>
</div>
</template>
ProjectForm.vue:
<script setup>
import { ref, toRef, reactive } from "vue"
import { useProjectStore } from '@/stores/ProjectStore.js'
import Input from './Input.vue'
const projectStore = useProjectStore()
const showAddType = ref(false)
//Capture 'showAddEntry' prop from parent component
const props = defineProps(['showAddEntry', 'editing', 'project'])
//Copy prop values for the form
const projName = toRef(props.project.project)
const projId = toRef(props.project.id)
//new/edited values are stored on this reactive object
const formState = reactive({
invalid: false,
errMsg: ""
})
const saveProject = () => {
formState.invalid = false
if(projId.value) {
console.log(`Update existing project ${projId.value}`)
projectStore.updateProject({
id: projId.value,
project: projName.value
})
.then(()=> {
console.log("save was successful!")
showAddType.value = false
formState.invalid = false
formState.errMsg = ""
emit('hideForm')
})
.catch(err=>console.log("Error: ", err))
} else {
console.log(`Create new project`)
//New Project
projectStore.createProject({
project: projName.value,
})
.then(()=> {
showAddType.value = false
formState.invalid = false
formState.errMsg = ""
emit('hideForm')
})
}
}
const hideForm = ()=> {
formState.invalid = false
showAddType.value=false
emit('hideForm')
}
//Define emit event up to the parent that hides the form
const emit = defineEmits(['hideForm'])
</script>
<template>
<div class="addform" :class="{ show: props.showAddEntry }">
<h1 v-if="editing" class="title">Edit Project</h1>
<h1 v-else class="title">Add New Project</h1>
<div class="input-wrap" :class="{ 'input-err' : formState.invalid }">
<Input
@input="projName = $event.target.value"
type="text"
placeholder="Enter project name"
:value="projName"
/>
<div class="entry-submit">
<button v-if="editing" @click="saveProject">Save</button>
<button v-else @click="saveProject">Create Project</button>
<button @click="hideForm">Cancel</button>
</div>
</div>
<p v-show="formState.invalid" class="err-msg">{{ formState.errMsg }}</p>
</div>
</template>
答案1
得分: 1
ProjectDetails.vue
中的 project
不知道在存储中对它所做的更改。如果你用 computed()
包裹它,它就会知道。
import { computed } from 'vue'
const project = computed(() => projectStore.getProjectById(id))
英文:
project
in ProjectDetails.vue is not aware of changes being made to it in the store. It will if you wrap it with computed()
import { computed } from 'vue'
const project = computed(() => projectStore.getProjectById(id))
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论