从 vue-router 调用后 Vue 3 组件未更新

Vue 3 component not updating after call from vue-router

我想用 ionic-vue 构建一个待办事项应用程序。它目前使用 vue 3。 我有这个概述(称为 Lists.vue),可以在其中单击多个列表(每个列表应加载任务)。但是,每次我点击一个列表时,都会出现相同的数据!就好像组件被重用但没有重新渲染/更新。

我尝试了各种解决方案。其中之一是在正在更改的裁判上应用手表,但是,没关系,最终结果保持不变。也试过给 router-link :key,还是不行。

我的Lists.vue

  <ion-page>
    <ion-content v-if="chunk" class="flex flex-col overflow-auto ion-align-self-center content-wrapper">
        <ion-toolbar class="mt-2">
            <h1 class="text-4xl pl-5 font-semibold">Lijsten</h1> 
        </ion-toolbar>
        <div v-for="(categoryChunk, index) in chunk.value" :key="index"  class="flex flex-wrap w-full flex-row justify-around mt-2">
            <div v-for="category in categoryChunk" :key="category.id">
                <ion-card class='w-40 sm:w-80'>
                    <router-link :to="{ name: 'Index', params: {categoryId: category.id} }">
                        <ion-card-header class="flex">
                            <ion-icon class="mt-5 text-4xl" color="orange-secondary" :icon="allIcons[category.icon]"></ion-icon>
                            <div class="m-4"> 
                                <p><b>{{ category.title }}</b></p>
                                <p>Taken: {{ category.tasks }}</p>
                            </div>
                        </ion-card-header>
                        <ion-card-content><div class="line-vert"></div></ion-card-content>
                    </router-link>
                </ion-card>
            </div>
        </div>
    </ion-content>
     <div v-else>  
         <ion-spinner class="centered" color="orange" name="crescent"></ion-spinner>
    </div>
    <ion-fab vertical="bottom" horizontal="end" slot="fixed">
        <ion-fab-button color="orange-secondary" @click="setOpen(true)">
            <ion-icon class="text-4xl" color="light" :icon="allIcons.add"></ion-icon>
        </ion-fab-button>
    </ion-fab>
    <ion-modal
        :is-open="isOpenRef"
        css-class="my-custom-class"
    >
        <create-list v-on:on-close="setOpen(false)"></create-list>
  </ion-modal>
  </ion-page>
</template>

<script>
import { defineComponent, computed, ref, watch, onBeforeMount } from "vue";
import {
    IonPage, 
    IonCard, 
    IonCardHeader, 
    IonIcon, 
    IonCardContent,
    IonFab,
    IonFabButton,
    IonContent,
    IonToolbar,
    IonModal,
    IonSpinner,
    } from '@ionic/vue'

import  * as allIcons  from 'ionicons/icons'
import getCollection from "../../composables/getCollection"
import CreateList from './CreateList'

export default defineComponent ({
    components: {
        IonPage,
        IonCard,
        IonCardHeader, 
        IonIcon,
        IonCardContent,
        IonFab,
        IonFabButton,
        IonContent,
        IonToolbar,
        IonModal,
        CreateList,
        IonSpinner,
    },

    setup() {
        const { loadCollection } = getCollection();
        const chunk = ref()

        // Zet modal open/dicht
        const isOpenRef = ref(false);
        const setOpen = (state) => isOpenRef.value = state;
        
        // Laad alle categorieën uit de database 
        const reload = () => {
            loadCollection('categories').then(data => {
                chunk.value = computed(() => {
                    // Zet de items uit de database om in delen van twee.
                    const array = [];
                    const size = 2;
                    for(let i = 0; i < data.length; i += size) {
                        array.push(data.slice(i, i+size));
                    }
                    return array;
                })
            })
        }

        onBeforeMount(() => {
            reload();
        })

        watch(isOpenRef, () =>{
            reload()
        })
        
        return {
            allIcons,
            chunk,
            isOpenRef,
            setOpen,
        }
    }
})
</script>

我的列表名为 Index.vue(也许我应该将其命名为 list.vue 或其他...)

<template>
    <ion-page>
        <ion-content v-if="category">
            <ion-toolbar>
                <div class="flex justify-between">
                    <h1 class="font-light pl-5">{{ category.title }}</h1>
                    <ion-icon class="text-2xl pr-5" :icon="closeOutline"  @click="redirectBack()"></ion-icon>
                </div>
            </ion-toolbar>
            {{ category }}
        </ion-content>
        <div v-else>  
            <ion-spinner class="centered" color="orange" name="crescent"></ion-spinner>
        </div>
    </ion-page>
</template>

<script>
import { defineComponent, ref } from "vue";
import  { closeOutline }  from 'ionicons/icons'

import { 
    IonPage,
    IonContent,
    IonToolbar,
    IonIcon,
    IonSpinner,
} from '@ionic/vue'
import { useRoute, useRouter } from "vue-router";
import getValue from "@/composables/getValue";

export default defineComponent ({
    components: {
        IonPage,
        IonContent,
        IonToolbar,
        IonIcon,
        IonSpinner
    },

    setup() {
        const router = useRouter()
        const route = useRoute()
        const { loadValue } = getValue()
        const category = ref()

        // redirect terug naar lists indien men op kruisje klikt.
        const redirectBack = () => {
            return router.push({name: 'Lists'})
        }
        
        // Ophalen van data van een lijst.
        loadValue('categories', route.params.categoryId).then(data => {
            category.value = data
        })

        return {
            closeOutline,
            redirectBack,
            category,
        }
    }
})
</script>

我的可组合函数:

import {ref } from "@vue/reactivity";
import { todoFirestore } from "../firebase/config";

const getValue = () => {
    const error = ref(null);

    const loadValue = async (collectionName: string, id : string) => {
        try {
           let res = await todoFirestore.collection(collectionName).doc(id)
           .get();

           if (!res.exists) {
               throw Error('Lijst bestaat niet.');
           }

           return { ...res.data(), id: res.id }
        }
        catch (err) {
            error.value = err.message
        }
    }
    return { error , loadValue }
}

export default getValue;

如果有人知道任何可能的解决方案,或者我可能做错了什么,请帮忙!非常感谢所有解决方案。

PS: 由于情况,我目前不能很快回复,但我向你保证,我会回复你的答案:)

找到了我的问题的答案!我必须在 loadValue 方法上使用 watchEffect 才能从数据库中调用数据。看起来Vue(在互联网上做了一些研究)希望重用组件而不是重新渲染它们,这样效率更高。

路由参数正在更新,但是组件的密钥没有。

Index.vue(任务列表)上的设置函数

 setup() {
        const router = useRouter()
        const route = useRoute()
        const { loadValue } = getValue()
        const category = ref()

        // redirect terug naar lists indien men op kruisje klikt.
        const redirectBack = () => {
            return router.push({name: 'Lists'})
        }
       
        // Ophalen van data van een lijst.
        const getCategory = () => {
            loadValue('categories', route.params.categoryId).then(data => {
                category.value = data
            })
        }

        watchEffect(() => {
            getCategory()
        })

        return {
            closeOutline,
            redirectBack,
            category,
        }