1

I have a very simple wrapper composable to manage backend get requests

// 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 };
}

When using this composable, i have trouble accessing my data values.

<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>

I do expect to get my data object in the latter log. The 'null' confuses me, considering the data object is indeed reactive. It seems that vue internally converted the ref to a reactive. But any then i should be able to access this object by data.dataPropertyName, which i cannot. I don't fully see through this. I do appreciate any help to fully understand what is going on here.

haligh
  • 9
  • 3
  • your console.log is not waiting for the data.value to change. you need a computed() or watch(Effect)() to listen when the variable is changing – Sysix Apr 18 '23 at 16:34
  • Possible duplicate of https://stackoverflow.com/questions/23429203/weird-behavior-with-objects-console-log – Estus Flask Apr 18 '23 at 20:13

2 Answers2

0

You simply check your data with the console.log() before it is loaded.

UPDATE

The playground demonstrates the problem you have.

  1. Data property is defined const data = ref(null);
  2. Axios request is started
  3. The current value of the data property is logged and it is equals null, since the request is not yet done.
  4. Request is done and the data property is filled with the request data.

So, you are trying to get the value from the data property, before the axios request is done. That's why the console.log(data.value); logs 'null'.

The playground does not really provide a solution for the problem. If you want to process the data right after it's loaded, then you should use Promises or async/await.

If you want to watch your data property and react to data changes, then create a watcher.

watch(() => data.value...., (val) => {....})

UPDATE 2

If you want to log your data after the request is done, then put the console.log(data.value) into .then()

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

To use the data, you have to wait till it is loaded. You can do it in several ways.

For example, you could watch the isLoaded property.

in useAxiosGet.js

const isLoaded = ref(false);

and

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

and watcher for isLoaded

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

I have updated the playground with the watcher

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>
Tolbxela
  • 4,767
  • 3
  • 21
  • 42
  • I do understand that i cannot just log the way i did. I do not understand why your logData would solve that problem. Now the logging is delayed to the point when you execute it, but in case date has not fetched up to that point, the error remains. Using – haligh Apr 21 '23 at 08:55
  • ```const getData = computed(() => data.value)``` to then do ```const logData = () => console.log(getData)``` should do the job from my understanding. It does not though. – haligh Apr 21 '23 at 09:06
  • Maybe i should invert my question. How does a ```useAxiosGet()``` function look, that lets me use my data in this way: ```const data = useAxiosGet(testUrl); console.log(data.id); useMyData(data);``` – haligh Apr 21 '23 at 12:22
  • I have added the new update. – Tolbxela Apr 21 '23 at 13:26
  • 1
    This is incredibly useful! – haligh Apr 21 '23 at 19:30
0

I wouldnt able explain the code completely. But I see the issue is related to the timing of when the data is being fetched from the backend and when it is being accessed in the component.

So in the code, useAxiosGet, I see that watchEffect hook to fetch data from the backend and update the data ref when it is available.

Also, when the component that uses this composable is mounted, the data ref seems to be still null, just the watchEffect in the code has not yet run and updated the data ref with the fetched data.

  • try using the computed property to gain access to 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>

  • or you could just use the watch function
 <script setup>
    const { data } = useAxiosGet('my/path/to/backend/');
    
    watch(data, (newVal) => {
      console.log(newVal); // should log the fetched data
    });
 </script>

any of the above should give you access

Tolbxela
  • 4,767
  • 3
  • 21
  • 42
Joypal
  • 178
  • 9