我正在试用composable example,但我似乎不能让它工作.

// fetch.js
import { ref } from 'vue'

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

  fetch(url)
    .then((res) => res.json())
    .then((json) => (data.value = json))
    .catch((err) => (error.value = err))

  return { data, error }
}

通过以下方式调用:

<script setup>
import { useFetch } from './fetch.js'

const { data, error } = useFetch('...')
</script>

但是,如果我记录data,它是空的吗?

推荐答案

fetch()成功完成之前,data将为空,您可能正在更早地访问它.

根据您希望处理加载状态的方式,您可以将useFetch()设置为异步,并在async setup中使用它:

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

  try {
    data.value = await fetch(url).then(res => res.json())
  } catch(err) {
    error.value = err
  }

  return { data, error }
}

然后在组件中:

const { data, error } = await useFetch()

或者,您还返回Promise或布尔值,以便组件可以检测数据是否正在加载.类似于:

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

  const doFetch = () => {
    isLoading.value = true
    loadingPromise.value = fetch(url)
      .then((res) => res.json())
      .then((json) => (data.value = json))
      .catch((err) => (error.value = err))
      .finally(() => isLoading.value = false)
  }
  doFetch()

  return { data, error, loadingPromise, isLoading}
}

实际上,您可以像使用异步版本一样使用它,方法是在安装过程中等待返回的promise .

以下是它的一个片段:

const { createApp, ref, defineAsyncComponent } = Vue;

function useFetch(url) {
  const data = ref(null)
  const error = ref(null)
  const loadingPromise = ref()
  const isLoading = ref(false)

  const doFetch = () => {
    isLoading.value = true
    loadingPromise.value = new Promise(resolve => setTimeout(resolve, 2000))
      .then(() => [1,2,3])
      .then((json) => (data.value = json))
      .catch((err) => (error.value = err))
      .finally(() => isLoading.value = false)
  }

  doFetch()

  return { data, error, loadingPromise, isLoading}
}

const AsyncSetupComponent = {
  template: `<pre>{{data}}</pre>`,
  async setup(){
    const {data, loadingPromise} = useFetch()
    await loadingPromise.value
    return {data}
  }
}

const ComponentWithLoading = {
  template: `
    <div v-if="isLoading">Loading...</div>
    <pre v-else>{{data}}</pre>
  `,
  setup(){
    const {data, isLoading} = useFetch()
    return {data, isLoading}
  }
}



const App = {
  components: {AsyncSetupComponent, ComponentWithLoading},
  template: `
    <div class="box">
    Async setup component with suspense:
    <suspense>
      <AsyncSetupComponent/>
      <template #fallback>Loading...</template>
    </suspense>
    </div>
    <div class="box">
      Component with loading:
      <ComponentWithLoading/>
    </div>
  `
}
createApp(App).mount('#app')
.box{
  border: 1px solid pink;
  margin: 4px;
}
<div id="app"></div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>

Vue.js相关问答推荐

Vuetify快速失败不会阻止发送表单

为什么在 Vue2 中调用 this.$emit() 后 props 没有立即更新?

Vue 3 范围滑块中的多个值

Webpack 编译错误:TypeError: __WEBPACK_IMPORTED_MODULE_1__ … is not a function

如何 for each 用户分组聊天消息?

Vue CLI - 编译后将配置文件保留为外部

如何将 vuejs 项目部署到 heroku

在 Vue.js 中动态挂载单个文件组件

如何在 Vue 中编译从外部 api 加载的模板

未捕获的类型错误:无法读取未定义的属性initializeApp

如何将 vue.js 与 gulp 一起使用?

如何判断 Vue 组件是否处于活动状态

Vuejs在复选框 Select 上切换div可见性

如何从 vue.js 中的自定义组件中冒泡点击事件?

在 Vue.js 中,为什么我们必须在导入组件后导出它们?

Vuex:无法读取未定义的属性'$store'

是否可以从 vue-devtools 中排除 vue 事件和 vuex Mutations?

Vue CLI 3 sass-resources-loader - Options.loaders 未定义

Vuejs - 使用 v-if 切换的保持活动组件

Vue中的嵌套循环