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

Vue3中useFetch获取的数据无法作为数组循环的问题

问题描述

我使用Vuejs.org提供的组合式函数useFetch:

// fetch.js
import { ref, isRef, unref, watchEffect } from 'vue'

export function useFetch(url) {
  const data = ref(null)
  const error = ref(null)

  function doFetch() {
    // reset state before fetching..
    data.value = null
    error.value = null
    // unref() unwraps potential refs
    fetch(unref(url))
      .then((res) => res.json())
      .then((json) => (data.value = json))
      .catch((err) => (error.value = err))
  }

  if (isRef(url)) {
    // setup reactive re-fetch if input URL is a ref
    watchEffect(doFetch)
  } else {
    // otherwise, just fetch once
    // and avoid the overhead of a watcher
    doFetch()
  }

  return { data, error }
}

在script标签中这样使用:

let loopableValues = ref([])
const { data, error } = useFetch(
  'https://jsonplaceholder.typicode.com/todos/',
)
loopableValues.value = data
return { loopableValues }

尝试在模板中循环时抛出错误:

<div v-for="value in loopableValues" :key="value.id"> {{ value.id}}</div>

错误信息:Uncaught (in promise) TypeError: value is undefined

我认为需要处理Promise,但不知道具体该怎么做,是要对useFetch返回的数据做处理,还是遗漏了其他步骤?


解决方案

问题出在两个核心点:

  1. 错误赋值ref对象:loopableValues.value = data 把data这个ref对象直接赋值给了loopableValues的value,导致loopableValues实际指向的是一个ref容器而非数组数据,循环时自然无法读取到数组项。
  2. 初始状态未处理:useFetch中data初始值为null,请求完成前模板循环null会触发value is undefined错误。

修正方案一:直接使用返回的data并处理初始状态

const { data, error } = useFetch('https://jsonplaceholder.typicode.com/todos/')
return { data, error }

模板中添加空值兜底:

<div v-for="value in data || []" :key="value.id"> {{ value.id}}</div>

修正方案二:正确赋值loopableValues

如果必须使用loopableValues,通过监听data的变化来同步数据:

import { ref, watch } from 'vue'
// ...
const loopableValues = ref([])
const { data, error } = useFetch('https://jsonplaceholder.typicode.com/todos/')

// 监听data变化,同步到loopableValues
watch(data, (newVal) => {
  loopableValues.value = newVal || []
}, { immediate: true })

return { loopableValues, error }

模板无需额外修改:

<div v-for="value in loopableValues" :key="value.id"> {{ value.id}}</div>

可选优化:给useFetch添加加载状态

为了提升用户体验,可以给useFetch扩展加载状态,方便在模板中处理加载中、出错场景:

// fetch.js
import { ref, isRef, unref, watchEffect } from 'vue'

export function useFetch(url) {
  const data = ref(null)
  const error = ref(null)
  const loading = ref(false) // 新增加载状态

  function doFetch() {
    data.value = null
    error.value = null
    loading.value = true // 标记加载中
    fetch(unref(url))
      .then((res) => res.json())
      .then((json) => (data.value = json))
      .catch((err) => (error.value = err))
      .finally(() => loading.value = false) // 加载结束
  }

  if (isRef(url)) {
    watchEffect(doFetch)
  } else {
    doFetch()
  }

  return { data, error, loading }
}

使用时的模板可以更友好:

<div v-if="loading">加载中...</div>
<div v-else-if="error">请求出错:{{ error.message }}</div>
<div v-else v-for="value in data || []" :key="value.id"> {{ value.id}}</div>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 21:15:40