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

Vue3中能否用watch监听原始值?加载组件不响应问题求助

问题

每次获取数据时,希望通过修改布尔值来渲染<Loading />组件,不想依赖数组长度作为判断条件,但<Loading />组件始终不响应state.isLoading的变化。尝试用watch测试this.isLoading是否变化,但watch从未输出日志。想咨询:Vue3中能否用watch监听原始值?若不可行,有没有类似React useEffect的替代方案?

相关代码

App.vue

<script setup>
  import { RouterView } from 'vue-router'
  import { watch, ref, onMounted, reactive } from 'vue';
  import Navbar from './components/Navbar.vue'
  import { useShopStore } from './stores/shopStore';

  const shop = useShopStore()

  const bool = ref(shop.isLoading)

  console.log(bool)

  watch(bool.value, (newBool) => {
    console.log(newBool)
  }, { deep: true })
</script>

Category.vue

<template>
  <LoadingVue v-if="shop.isLoading" />
  <div v-else class="category__menu">
    <CardVue
      v-for="item in shop.category"
      :item="item"
      :key="item.id"
    />
  </div>
</template>

ShopStore.js

actions: {
  async getProducts(path) {
    if (typeof path !== 'string' || path === undefined) return
    this.setLoading()
    try {
      const response = fetch(`https://fakestoreapi.com/products/category/${path}`)
      .then(res => res.json())
      .then(res => this.category = res)
    } catch (error) {
      console.log(error)
      alert('Something went wrong')
    }
    this.setLoading()
  },
  setLoading() {
    console.log('setLoading')
    this.isLoading = !this.isLoading
  }
}
解答

1. Vue3可以监听原始值,但你的写法有误

你当前用watch(bool.value, ...)直接监听的是一个原始布尔值,这个值只是shop.isLoading的初始快照,和store中的响应式状态没有关联——当store里的isLoading变化时,bool.value不会自动同步更新,所以watch自然不会触发日志。

正确的监听方式有两种:

  • 直接监听store中的响应式状态(前提是isLoading在store里用ref/reactive定义):
watch(() => shop.isLoading, (newVal) => {
  console.log(newVal)
})
  • 如果要通过bool中转,用计算属性同步响应式状态:
import { computed } from 'vue'

const bool = computed(() => shop.isLoading)
watch(bool, (newVal) => console.log(newVal))

2. Loading组件不响应的核心问题:异步逻辑顺序错误

你的getProducts标注了async,但内部用.then处理请求却没有加await,导致两次setLoading几乎同时执行:第一次打开loading后,请求还没完成,第二次关闭loading的代码就已经执行,最终isLoading相当于没有变化,视图自然不会更新。

修复后的异步逻辑:

async getProducts(path) {
  if (typeof path !== 'string' || path === undefined) return
  this.setLoading()
  try {
    const res = await fetch(`https://fakestoreapi.com/products/category/${path}`)
    const data = await res.json()
    this.category = data
  } catch (error) {
    console.log(error)
    alert('Something went wrong')
  } finally {
    // 用finally确保请求成功/失败都能关闭loading
    this.setLoading()
  }
}

3. 类似React useEffect的替代方案:watchEffect

Vue3的watchEffect和React useEffect逻辑一致,它会自动追踪回调中用到的响应式依赖,当依赖变化时自动执行回调,无需手动指定监听目标:

import { watchEffect } from 'vue'

watchEffect(() => {
  // 自动监听shop.isLoading的变化
  console.log(shop.isLoading)
})

它会在组件挂载时执行一次,之后每次依赖更新都会重新执行,适合处理各类副作用逻辑。

内容的提问来源于stack exchange,提问作者thirtythreeboas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 01:55:16