Search code examples
vuejs3vue-componentvue-composition-apipinia

Vue 3 component doesn't update after pinia store is updated


I'm working on a Vue js 3 project using typescript and Pinia.

I have a modal that creates a changelog it works well, the changelog is created but the view is not updated, I need to refresh the page to be displayed.

<template>
  <div class="flex px-4">
    <CreateChangelogModal/>
  </div>
  <main>
    <div class="grid grid-cols-1 gap-4 place-items-center mt-10 md:mt-28">
      <template v-if="changelogStore.filteredChangelogs?.length">
        <ChangelogCard
          class="mb-2.5"
          v-for="changelog in changelogStore.filteredChangelogs"
          :id="changelog.id"
          :date="changelog.date"
          :type="changelog.type"
          :title="changelog.title"
          :app_name="changelog.app_name"
          :content="changelog.content"
          :key="changelog.id"
        />
      </template>
      <div v-else class="text-center p-4">
        <p>No changelogs to display</p>
      </div>
    </div>
  </main>
</template>

<script setup lang="ts">
const changelogStore = useChangelogStore()

onMounted(async () => {
  if (changelogStore.changelogs.length === 0) {
    await changelogStore.fetchChangelogs()
  }
})
</script>

My store, changelogsStore.ts :

export const useChangelogStore = defineStore('changelogs', {
  state: () => ({
    changelogs: [] as ChangelogInterface[],
    searchQuery: ''
  }),

  getters: {
    filteredChangelogs: (state) => {
      const searchLower = state.searchQuery.toLowerCase()
      return state.changelogs.filter((changelog) => {
        return changelog.title.toLowerCase().includes(searchLower) ||
               changelog.date.includes(searchLower) ||
               changelog.type.toLowerCase().includes(searchLower)
      })
    }
  },

  actions: {
    setSearchQuery(newQuery: string) {
      this.searchQuery = newQuery
    },

    async fetchChangelogs(lastChangelogId?: number) {
      try {
        const newChangelogs = await changelogService.getAllChangelogs(lastChangelogId)
        if (newChangelogs.length > 0) {
          this.changelogs.push(...newChangelogs)
        }
        return newChangelogs
      } catch (error) {
        console.error('Failed to fetch changelogs:', error)
        return []
      }
    },

    async generateChangelog(changelogData: ChangelogInterface) {
      try {
        const newChangelog = await changelogService.createChangelog(changelogData)
        console.log('FROM THE STORE GENERATE CHANGELOG' ,changelogData)
        this.changelogs.push(newChangelog)
      } catch (error) {
        console.error('Failed to create changelog:', error)
      }
    },

And the form that creates the changelog (not sure if the problem comes from there but just to be sure) :

<script lang="ts" setup>
const changelogUseCase = new ChangelogsUsecases()

const createChangelog = async (formData: ChangelogInterface) => {
  try {
    const newChangelog = await changelogUseCase.createChangelog(formData)
    if (newChangelog) {
      // NOT SO SURE ABOUT changelogStore.changelogs.push(newChangelog)
      // changelogStore.fetchChangelogs(newChangelog.id)

    }
  } catch (error) {
    console.error('Error while creating new changelog :', error)
  }
}

const onSubmit = handleSubmit(async (values) => {
  const validData: ChangelogInterface = {
    title: values.title,
    type: values.type,
    date: values.date,
    content: values.content,
    app_name: values.app_name
  }

  await createChangelog(validData)
})
</script>

I tried to only display the code needed that could be the issue.

Thanks !


Solution

  • I found where the problem was, when manipulating array in Vue some operations on arrays may break reactivity, in my store I had : this.changelogs.push(...[newChangelog])

    But with this it's finally working as intended ! this.changelogs.splice(...[newChangelog])

    Thank you @Boris for your kind help !