Vue 3可组合引用行为

eivnm1vs  于 2023-04-21  发布在  Vue.js
关注(0)|答案(2)|浏览(193)

我有一个非常简单的 Package 器组合来管理后端get请求

// inside useAxiosGet.js
import { ref, watchEffect } from 'vue';
import axios from 'axios';
export default function (url) {
  const data = ref(null);

  watchEffect(async () => {
    axios({
      url: url
    })
      .then((res) => {
        data.value = res.data;
      })
      .catch((err) => console.log(err));
  });

  return { data };
}

使用此组合时,我在访问数据值时遇到了问题。

<script setup>
const { data } = useAxiosGet('my/path/to/backend/');
console.log(data); // logs the usual wrapper around refs, where i find my data under '_rawValue'.
console.log(isRef(data)) // logs a true - the object didnt lose reactivity while destructuring.
console.log(data.value); // logs 'null'.
</script>

我确实希望在后一个日志中得到我的数据对象。'null'让我感到困惑,考虑到数据对象确实是React性的。看起来vue内部将ref转换为React性的。但是无论如何,我应该能够通过data.dataPropertyName访问这个对象,我不能。我没有完全看到这一点。我非常感谢任何帮助,以充分理解这里发生的事情。

i2loujxw

i2loujxw1#

我无法完全解释代码,但我发现这个问题与从后端获取数据的时间以及在组件中访问数据的时间有关。
因此,在代码useAxiosGet中,我看到watchEffect钩子从后端获取数据,并在data ref可用时更新它。
此外,当安装使用此组合的组件时,data ref似乎仍然是null,只是代码中的watchEffect尚未运行并使用获取的数据更新data ref。

  • 尝试使用computed属性访问data
<script setup>
    const { data } = useAxiosGet('my/path/to/backend/');
    
    const formattedData = computed(() => {
      return data.value;
    });
    
    console.log(formattedData.value); // should log the fetched data
 </script>
  • 也可以使用watch函数
<script setup>
    const { data } = useAxiosGet('my/path/to/backend/');
    
    watch(data, (newVal) => {
      console.log(newVal); // should log the fetched data
    });
 </script>

以上任何一项都可以给予您访问

wqsoz72f

wqsoz72f2#

您只需在加载console.log()之前使用它检查数据。

更新

操场展示了你的问题。
1.数据属性定义为const data = ref(null);

  1. Axios请求已启动
    1.记录数据属性的当前值,它等于null,因为请求尚未完成。
    1.请求已完成,并且数据属性已填充请求数据。
    因此,您试图在axios请求完成之前从data属性中获取值。这就是为什么console.log(data.value);记录'null'。
    playground并没有真正提供这个问题的解决方案。如果你想在数据加载后立即处理它,那么你应该使用Promisesasync/await
    如果你想观察你的数据属性并对数据变化做出React,那么创建一个watcher
watch(() => data.value...., (val) => {....})

更新2

如果希望在请求完成后记录数据,则将console.log(data.value)放入.then()

.then((res) => {
    data.value = res.data;
    console.log(data.value)
 })

要使用这些数据,你必须等到它被加载。你可以用几种方法来做。
例如,您可以查看isLoaded属性。
正在使用AxiosGet.js

const isLoaded = ref(false);

.then((res) => {
    data.value = res.data;
    isLoaded.value = true;
 })

isLoaded的监视器

watch(() => isLoaded.value, () => useMyData(data))

我已经用watcher更新了Playground

const { createApp, ref, watch, watchEffect, isRef } = Vue;

const useAxiosGet = (url) => {
  const data = ref(null);
  const isLoaded = ref(false); 
  watchEffect(async () => {
    axios({
      url: url
    })
      .then((res) => {
        data.value = res.data;
        isLoaded.value = true;
      })
      .catch((err) => console.log(err));
  });
  watch(() => isLoaded.value, () => console.log(data.value))
  return { data, isLoaded };
}

const app = createApp({
  setup () {  
    const { data } = useAxiosGet('https://jsonplaceholder.typicode.com/todos/1');
    console.log(data); // logs the usual wrapper around refs, where i find my data under '_rawValue'.
    console.log(isRef(data)) // logs a true - the object didnt lose reactivity while destructuring.
    console.log(data.value); // logs 'null'. 
    const logData = () => console.log(data.value);
    return { data, logData }
  }
})

app.mount('#app')
<div id="app">
data: {{ data }}<br/>
<button @click="logData()">log</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

相关问题