2

I have a custom hook to fetch data that is looking like this:

import { reactive } from 'vue';
import axios from 'axios';

interface State {
  isLoading: boolean;
  isError: boolean;
  errorMessage: string,
  data: object|null
}

export default function useAxios(url: string, data: object) {
  const state = reactive({
    isLoading: true,
    isError: false,
    errorMessage: '',
    data: null
  }) as State;

  const fetchData = async () => {
    try {
      const response = await axios({
        method: 'GET',
        url: url, // '/test_data/campaign.json'
        data: data
      });
      state.data = response.data;
    } catch (e) {
      state.isError = true;
      state.errorMessage = e.message;
    } finally {
      state.isLoading = false;
    }
  };

  return {
    toRefs(state), //TS complains over "Parameter 'state' implicitly has an 'any' type." But it's already typed in the above???
    fetchData
  };
}

Im trying to use this in my custom component, but I keep getting that data is undefined, even though I can see the data if I do a console.log() in my custom hook where im calling the endpoint and logging the response...

Im trying to use it like this

setup() {
    const state = reactive({
      data: null
    });
    const {data, isLoading, fetchData} = useAxios(
      '/test_data/campaign.json',
      {}
    );
    const getCampaignData = async () => {
      await fetchData();
      console.log('data', data);
      state.data = data;
    };

    onMounted(() => {
      getCampaignData();
    });

    return {
      data: state.data
    };
  }

What am I doing wrong here? In the hook, response.data has the data from the JSON file, but when calling the data from the hook in my component, it's null ?

1
  • I think you need to await fetchData() in your component seeing that it is an async function. Commented Mar 8, 2021 at 19:10

1 Answer 1

1

In composable function try to not spread the state since it loses its reactivity, you could use toRefs to return a reactive ref :

import {reactive,toRefs} from 'vue';
import axios from 'axios';

export default function useAxios(url: string, data: object) {
....
  return {
    ...toRefs(state),
    fetchData
  }
}

then in your component call that composable function outside the getCampaignData function like :

import {reactive,toRefs,onMounted} from 'vue';
setup() {
    const state = reactive({
      data: null
    });
 const { data, isLoading, fetchData } = useAxios(
        '/test_data/campaign.json',
        {}
      );
    const getCampaignData = async () => {
     
      await fetchData();
      
      state.data = data.value;
    };

    onMounted( ()=>{
        getCampaignData();
    })

    return {
      ...toRefs(state)
    };
  }
Sign up to request clarification or add additional context in comments.

4 Comments

thx i've updated my example, but cant get it to work, as the toRefs() function complains over state in any, even though is is already typed? If i directly type in the the toRefs() like so: toRefs(state: State) - I get a parsing error
you're welcome, please try out return{... toRefs(state),fetchData}
Ahhh, yeah, that works... However, for getting the data in the component, now I need to do: data.value.something for getting the data.... Isn't it possible to avoid having the .value on the object, and just get the data as is ? eg my data exists in a data property... now it seems like I have to to: data.value.data instead of just data.data ?
No, since toRefs converts the state to ref which should be accessed using value property

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.