Vue未调用onMounted钩子导致Composable内ref数组为空问题咨询
核心原因
- 你的
useLocations是状态不共享的普通composable,每次调用都会生成独立的状态实例,不同调用返回的locationsref完全不是同一个对象,你在Vue开发者工具里看到的有值的locations是其他地方调用useLocations生成的实例,本次watch回调里调用生成的新实例的locations是刚初始化的空数组。 - 你在watch的handler中调用
useLocations时,组件已经完成挂载,composable内部的onMounted钩子回调不会再触发,getLocations永远不会执行,新实例的locations永远不会被赋值,自然一直是空。 - 额外问题:你组件的props声明
props: [,'location']多了多余的逗号,属于语法错误,会导致props接收异常。
修复方案
方案1:将composable改为全局单例,共享同一份状态
适合locations是全局通用数据、不需要每个组件单独拉取的场景,修改Locations.js:
import { ref, isRef } from 'vue'; // 将状态和方法提到函数作用域外,全局唯一 const locations = ref([]); const loadImageData = (locId) => { isRef(locations); locations.value.forEach( (loc,key) => { console.debug( loc.id, locId ) }) }; const getLocations = async () => { // 避免重复请求 if (locations.value.length) return const locs = await apiFetch({ path: '/wp/v2/tour-location'}); locations.value = locs; }; // 初始化时直接拉取数据,不需要绑定组件生命周期 getLocations(); export default function useLocations () { return { locations, getLocations, loadImageData, }; }
方案2:组件内复用同一个composable实例,调整执行时机
如果locations需要按组件实例隔离,修改App.vue:
<template> <div class="location"> <h1>{{ location.name }}</h1> <img :src="location.main_image" /> </div> </template> <script> import useLocations from '@/composables/Locations'; export default { name: 'Location', props: ['location'], // 修正语法错误 setup() { // 组件生命周期内仅调用一次,复用同一个实例 return useLocations(); }, watch: { location: { immediate: true, handler: function(newLocation) { // 等待locations加载完成后再执行逻辑 const run = () => this.loadImageData(newLocation.id) if (this.locations.length) { run() } else { const unwatch = this.$watch('locations', (newVal) => { if (newVal.length) { run() unwatch() } }, { deep: true }) } } } }, } </script>
内容的提问来源于stack exchange,提问作者JakeParis
相关产品推荐
相关产品推荐

