Bird
Raised Fist0
Vueframework~20 mins

Composable for API calls (useFetch pattern) in Vue - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
Vue Fetch Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ component_behavior
intermediate
2:00remaining
What does this Vue composable return after a successful fetch?

Consider this Vue 3 composable using the useFetch pattern. What will the data ref contain after the fetch completes successfully?

Vue
import { ref } from 'vue';

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

  fetch(url)
    .then(res => res.json())
    .then(json => {
      data.value = json;
      loading.value = false;
    })
    .catch(err => {
      error.value = err.message;
      loading.value = false;
    });

  return { data, error, loading };
}
AA ref containing the parsed JSON response from the API
BA ref containing the raw Response object from fetch
CA ref containing an error message string
DA ref containing the fetch Promise object
Attempts:
2 left
💡 Hint

Think about what res.json() returns and what is assigned to data.value.

❓ state_output
intermediate
2:00remaining
What is the value of loading after fetch fails?

In the same useFetch composable, what will the loading ref value be if the fetch call fails (e.g., network error)?

Vue
import { ref } from 'vue';

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

  fetch(url)
    .then(res => res.json())
    .then(json => {
      data.value = json;
      loading.value = false;
    })
    .catch(err => {
      error.value = err.message;
      loading.value = false;
    });

  return { data, error, loading };
}
Afalse
Btrue
Cnull
Dundefined
Attempts:
2 left
💡 Hint

Check what happens to loading.value in the catch block.

📝 Syntax
advanced
2:00remaining
Which option correctly adds an abort controller to cancel fetch?

You want to add an AbortController to the useFetch composable to cancel the fetch request if needed. Which option correctly implements this?

Vue
import { ref } from 'vue';

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

  // Add abort controller here

  fetch(url, { signal: controller.signal })
    .then(res => res.json())
    .then(json => {
      data.value = json;
      loading.value = false;
    })
    .catch(err => {
      if (err.name === 'AbortError') {
        error.value = 'Fetch aborted';
      } else {
        error.value = err.message;
      }
      loading.value = false;
    });

  return { data, error, loading, controller };
}
Aconst controller = AbortController();
Bconst controller = new AbortController();
Cconst controller = new AbortController;
Dconst controller = AbortController;
Attempts:
2 left
💡 Hint

Remember how to correctly instantiate a class in JavaScript.

🔧 Debug
advanced
2:00remaining
Why does this composable never update data?

Look at this composable code. Why does data remain null even after the fetch completes?

Vue
import { ref } from 'vue';

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

  async function fetchData() {
    try {
      const res = await fetch(url);
      const json = await res.json();
      data = json;
      loading.value = false;
    } catch (err) {
      error.value = err.message;
      loading.value = false;
    }
  }

  fetchData();

  return { data, error, loading };
}
ABecause error is not handled
BBecause fetch is not awaited properly
CBecause loading is never set to false
DBecause 'data = json;' overwrites the ref instead of setting 'data.value'
Attempts:
2 left
💡 Hint

Remember how to update a Vue ref's value.

🧠 Conceptual
expert
2:00remaining
Why use a composable for API calls in Vue 3?

What is the main advantage of using a composable like useFetch for API calls in Vue 3 applications?

AIt replaces the need for Vuex or Pinia state management
BIt automatically caches API responses without extra code
CIt allows reusing reactive fetching logic across multiple components easily
DIt forces all API calls to be synchronous
Attempts:
2 left
💡 Hint

Think about code reuse and reactive state in Vue 3.

Practice

(1/5)
1. What is the main purpose of a composable like useFetch in Vue?
easy
A. To fetch data from an API and manage loading and error states reactively
B. To style components with CSS variables
C. To create Vue directives for DOM manipulation
D. To define routes in a Vue application

Solution

  1. Step 1: Understand composable role

    A composable in Vue is a reusable function that encapsulates logic, often for state or side effects.
  2. Step 2: Identify useFetch purpose

    The useFetch composable specifically handles API calls and manages reactive states like loading and error.
  3. Final Answer:

    To fetch data from an API and manage loading and error states reactively -> Option A
  4. Quick Check:

    Composable useFetch = fetch + reactive states [OK]
Hint: Composable useFetch manages API data and states reactively [OK]
Common Mistakes:
  • Confusing composables with styling or routing
  • Thinking composables only handle UI rendering
  • Assuming composables are Vue components
2. Which of the following is the correct way to import and use a useFetch composable in a Vue component?
easy
A. const { useFetch } = Vue; const result = useFetch(url);
B. import useFetch from 'vue'; const data = useFetch(url);
C. import { useFetch } from '@/composables/useFetch'; const { data, error } = useFetch(url);
D. import { fetchData } from '@/composables'; fetchData(url);

Solution

  1. Step 1: Check import syntax

    The composable is usually exported from a file and imported with curly braces if it's a named export.
  2. Step 2: Using the composable

    Calling useFetch(url) returns reactive properties like data and error.
  3. Final Answer:

    import { useFetch } from '@/composables/useFetch'; const { data, error } = useFetch(url); -> Option C
  4. Quick Check:

    Correct import + destructure = import { useFetch } from '@/composables/useFetch'; const { data, error } = useFetch(url); [OK]
Hint: Import named composable and destructure returned refs [OK]
Common Mistakes:
  • Importing from wrong path or package
  • Using default import when composable is named export
  • Not destructuring returned reactive properties
3. Given this useFetch composable usage:
const { data, loading, error } = useFetch('https://api.example.com/items');

What will loading.value be immediately after calling useFetch?
medium
A. null
B. true
C. false
D. undefined

Solution

  1. Step 1: Understand loading state in useFetch

    Loading usually starts as true when the fetch begins to indicate data is being fetched.
  2. Step 2: Check initial loading value

    Immediately after calling, loading is true until data or error updates it to false.
  3. Final Answer:

    true -> Option B
  4. Quick Check:

    Loading starts true during fetch [OK]
Hint: Loading is true while fetching data [OK]
Common Mistakes:
  • Assuming loading starts false before fetch
  • Confusing loading with data presence
  • Expecting loading to be null or undefined
4. What is the main issue with this useFetch composable snippet?
export function useFetch(url) {
  const data = ref(null);
  const loading = ref(false);
  const error = ref(null);

  fetch(url)
    .then(res => res.json())
    .then(json => { data.value = json; loading.value = false; })
    .catch(err => { error.value = err; loading.value = false; });

  loading.value = true;
  return { data, loading, error };
}
medium
A. Setting loading.value = true after fetch call starts causes race condition
B. Not using async/await causes syntax error
C. data should be initialized as an empty array, not null
D. Error ref should be initialized as an empty string

Solution

  1. Step 1: Analyze loading state timing

    Loading is set to false inside fetch callbacks but set to true after fetch starts, which can cause timing issues.
  2. Step 2: Identify race condition

    Because loading is set to true after fetch call, it might overwrite loading false set in callbacks if fetch resolves quickly.
  3. Final Answer:

    Setting loading.value = true after fetch call starts causes race condition -> Option A
  4. Quick Check:

    Loading state timing error = Setting loading.value = true after fetch call starts causes race condition [OK]
Hint: Set loading true before fetch call to avoid race [OK]
Common Mistakes:
  • Setting loading true after fetch call instead of before
  • Confusing async/await with promises syntax errors
  • Assuming initial data type must be array
5. You want to create a useFetch composable that automatically retries fetching up to 3 times if the API call fails. Which approach correctly adds this retry logic?
hard
A. Wrap fetch in a try/catch but do not retry on failure
B. Call fetch once and ignore errors, relying on component to retry
C. Use setTimeout outside the composable to call useFetch repeatedly
D. Use a recursive function inside the composable that calls fetch again on error until max retries reached

Solution

  1. Step 1: Understand retry logic needs repeated fetch calls

    Retry means calling fetch again if it fails, up to a limit.
  2. Step 2: Implement retry inside composable

    A recursive or loop function inside composable can retry fetch on error until max retries.
  3. Step 3: Evaluate other options

    Ignoring errors or retrying outside composable breaks encapsulation; try/catch without retry misses requirement.
  4. Final Answer:

    Use a recursive function inside the composable that calls fetch again on error until max retries reached -> Option D
  5. Quick Check:

    Retry logic inside composable = Use a recursive function inside the composable that calls fetch again on error until max retries reached [OK]
Hint: Retry fetch inside composable with recursion or loop [OK]
Common Mistakes:
  • Retrying outside composable losing reactive state control
  • Ignoring errors instead of retrying
  • Not limiting retry attempts causing infinite loops
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard