You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue项目Pinia store的getters初始加载时值不显示问题

Pinia 关联Getter初始加载不渲染问题修复

核心错误点

  • 跨store引用时机错误:在defineStore外层顶层调用useListProjets()、useListEntreprises(),此时Pinia还未完成store初始化,初始加载时拿到的projets、entreprises列表是空数组,匹配不到关联数据。打开Vue Devtools时会强制触发全量store的依赖收集和重算,所以数据才会临时显示。
  • Getter存在副作用:Pinia getter是纯计算属性,禁止直接修改原state数据。你当前写法在map遍历中直接给原始licence对象挂载name、responsable等属性,这类操作不会被Vue响应式系统正确追踪,数据变更不会触发视图更新。
  • 视图层未调用关联getter:currentList直接返回原始的$state.list,原始licence数据本身没有entreprise、name、responsable这些关联字段,模板首次渲染自然拿不到值。
  • 依赖追踪失效:零散拆分的多个getter没有被任何地方主动调用,不会在licence或projet数据变化时自动执行计算。
  • 缺失依赖引入:licence store中调用了useListEntreprises但未引入对应模块,会直接导致初始化异常。

修正后代码

1. 重写licence store

// src/stores/licence.js
import { defineStore } from "pinia";
import { useListProjets } from "./projets";
// 补全缺失的企业store引入
import { useListEntreprises } from "./entreprises";

export const useListLicences = defineStore({
  id: "licences",
  state: () => ({
    list: [],
  }),
  persist: true,
  getters: {
    // 单getter直接返回组装完成的全量许可证列表,不需要拆分零散方法
    getFullLicenceList: (state) => {
      // 跨store实例获取放在getter内部,确保Pinia初始化完成
      const projetsStore = useListProjets();
      const entreprisesStore = useListEntreprises();

      // 提前生成映射表代替双层循环,匹配效率更高
      const projetMap = new Map(
        projetsStore.list.map(projet => [projet.affaire, projet])
      );
      const entrepriseMap = new Map(
        entreprisesStore.list.map(ent => [ent.entreprise_nom, ent])
      );

      // 返回全新对象数组,不修改原始state数据,保持getter纯函数特性
      return state.list.map(licence => {
        const matchProjet = projetMap.get(licence.projet_affaire) || {};
        const matchEntreprise = entrepriseMap.get(matchProjet.entrepriseNom) || {};
        
        return {
          ...licence,
          name: matchProjet.projetNom || '',
          responsable: matchProjet.userPseudo || '',
          entreprise: matchProjet.entrepriseNom || '',
          affaire: matchProjet.affaire || '',
          ID_entreprise: matchEntreprise.id || '',
          contact1: matchProjet.email1 || ''
        }
      })
    }
  },
});

2. 修正视图页面逻辑

<template>
  <h1>Licences actives (de type "DEV")</h1>
  <table>
    <tr>
      <th>Numero/Clé</th>
      <th>Fin d'activation</th>
      <th>type</th>
      <th>Entreprise</th>
      <th>N° d'Affaire<br />(Projet)</th>
      <th>Projet</th>
      <th>Responsable</th>
      <th>Version</th>
      <th>Version Soft</th>
      <th>Durée restante <br />(jours)</th>
    </tr>

    <tr v-for="article in currentList" :key="article.numero">
      <td style="color: red">{{ article.numero }}</td>
      <td>{{ Date_formate(new Date(article.fin_activation)) }}</td>
      <td>{{ article.type }}</td>
      <td style="color: red">{{ article.entreprise }}</td>
      <td>{{ article.affaire }}</td>
      <td>{{ article.name }}</td>
      <td>{{ article.responsable }}</td>
      <td>{{ article.version }}</td>
      <td>{{ article.version_soft }}</td>
      <td>
        {{ Math.round((new Date(article.fin_activation) - Date.now()) / 86400000) }}
      </td>
    </tr>
  </table>
</template>

<script setup>
// 直接从vue引入组合式API,不要从@vue/runtime-core引入
import { computed } from "vue";
import { useListLicences } from "../stores/licence";
import { Date_formate } from "../plugin/functions";

const licenceStore = useListLicences();
// 直接调用组装好完整数据的getter,依赖变化时自动触发视图更新
const currentList = computed(() => licenceStore.getFullLicenceList);
</script>

开发注意事项

  • Getter必须是无副作用的纯函数,永远不要在getter里直接修改state值,所有计算结果通过返回值输出。
  • 跨store调用useXxxStore()方法,必须放在defineStore的getter/action回调内部,禁止在模块顶层执行,避免store未初始化问题。
  • 模板用到的计算字段,要确保computed/getter的依赖被正确追踪,不要直接读取原始state中不存在的字段。
  • 两个列表做关联匹配时,优先用Map生成映射表代替双层嵌套循环,性能更高,代码逻辑更清晰。

内容的提问来源于stack exchange,提问作者Amélie K.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 02:57:32