2

My problem is with using an Axios response in Vue.js; it seems that the data is not saved to the array (newBox).

I want to save API-returned values to an array for use with v-for in the component.

<script setup>
  import {
    RouterLink,
    RouterView
  } from 'vue-router';

  import {
    onMounted,
    onUnmounted
  } from 'vue'

  import Box from './components/Box.vue';

  import axios from "axios"
  import {
    propsToAttrMap
  } from '@vue/shared';

  var newBox = new Array();

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

  async function getPosts() {
    try {
      const url = `https://someurl.ir/api/v1/api.php`
      const response = await axios.get(url)
      this.newBox = response.data
      }))
    } catch (err) {
      if (err.response) {
        // client received an error response (5xx, 4xx)
        console.log("Server Error:", err)
      }
    }
  }
</script>

<template>
  <div class="NewBoxRibbon">
    <Box v-for="title in newBox" :msg="title" />
  </div>

  <RouterView />
</template>

<style scoped>
  .NewBoxRibbon{
    scrollbar-width: 0px;
    width: 100%;
    height: 450px;
    background-color: aquamarine;
    overflow-x: auto;
    white-space: nowrap;
  }

  ::-webkit-scrollbar {
    width: 0;
    /* Remove scrollbar space */
    background: transparent;
    /* Optional: just make scrollbar invisible */
  }
</style>

I used fetch and it too seems that in function getPosts it couldn't modify the array newBox...

Even when I define a variable and try to modify it in the function getPosts, can't do!!

1
  • Is that })) at the end of the try block in getPosts a typo? Unrelated to the question probably, but it is a fatal syntax error, and makes it just a little bit harder for us to test your code if we want to. Commented Oct 27, 2022 at 15:56

3 Answers 3

2

Define newBox as a ref property then update by reponse newBox.value = response.data:

 import {
    onMounted,
    onUnmounted,
    ref
  } from 'vue'

 // ....
  var newBox = ref([]);
//....

   const response = await axios.get(url)
     newBox.value = response.data

Sign up to request clarification or add additional context in comments.

2 Comments

Wouldn't the await be in an async function?
Yes, I just kept the relevant statement to make the answer more clear
2

Summary

  • Import ref from 'vue'
  • Define newBox as const newBox = ref([])
  • Use newBox as newBox.value instead of this.newBox
import { ref } from 'vue'

// ...

const newBox = ref([])

// ...

newBox.value = response.data

Full story

The reason why newBox is not being updated is that you are creating it as a plain array. In Vue, things that require reactivity (like v-for, computed properties, watchers, etc.) require you to use a ref of reactive object.

For example:

import { ref } from 'vue'

const newBox = ref([])

The value of the ref is then accessed on the .value property:

newBox.value = response.data

You do not need to use .value in the template in most cases, as it is automatically unwrapped (only a single level, so objects of refs will still require you to use .value, but that's probably more than you need to know right now).

Notes:

  • You do not need to use this in script setup, you can pretty much act as if it is a regular JS script.
  • Prefer let and const over var. For refs use const, as they are never reassigned.
  • Prefer array literals over the new Array() syntax.
  • I'm not sure what you are using propsToAttrMap for (I have never even heard of it), but if you really need it, at least import it from 'vue' not '@vue/shared'.

I have incorporated these notes into the following code, and left out the parts that are not directly relevant (HTML, onUnmounted, etc.). I have also removed the })) in the try block in getPosts, as they should not be there.

So your JS code would then look like this:

import { onMounted, ref } from "vue";

import axios from "axios";

const newBox = ref([]);

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

async function getPosts() {
  try {
    const url = `https://someurl.ir/api/v1/api.php`;
    const response = await axios.get(url);
    newBox.value = response.data;
  } catch (err) {
    if (err.response) {
      // client received an error response (5xx, 4xx)
      console.log("Server Error:", err);
    }
  }
}

Extra advice: you should almost always use the key attribute on the v-for element (List Rendering - Maintaining State with key).

Also, the Vue docs are excellent! Most questions can be answered just by reading the relevant section.

Useful doc links:

Hope this helps!

Comments

0

I agree with the previous answer. If you do not wrap the variable in a ref(), you are not using the reactivity part of the Composition API and thus the DOM is not updating.

It also appears you have extra closing parens in your try block, and note the 'this' keyword is not applicable in setup() functions. See VueJS docs regarding moving from Options API to Composition API and handling 'this'.

Finally, double-check that the response dot notation is correct. Are you certain that response.data is sufficient for traversing the JSON response or should it be response.data.posts perhaps? Console log the response to be sure.

<script setup>
import { RouterLink, RouterView } from "vue-router";
import { onMounted, ref } from "vue";
import Box from "./components/Box.vue";
import axios from "axios";

var newBox = ref([]);

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

async function getPosts() {
  try {
    const url = "https://someurl.ir/api/v1/api.php";
    const response = await axios.get(url);
    this.newBox.value = response.data.posts;
  } catch (err) {
    if (err.response) {
      // client received an error response (5xx, 4xx)
      console.log("Server Error:", err);
    }
  }
}
</script>

<template>
   <div class="NewBoxRibbon">
    <Box v-for="title in newBox" :msg="title" :key="title" />
  </div>

  <RouterView />
</template>

5 Comments

hi and thanks a lot!! one problem solved and another come! i dont know what to use instead of response.data.posts...
Depends on the server. Try console.log(response.data) after your axios.get() to see the data structure. Sometimes responses are sent as a ‘data’ object, so you may want to try response.data.data
(10) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}] its my response.data
<NewBookBox v-for="(book) in newBooks" :bookTitle="book.title"/> find it!! thanks a lot
Great! Glad to see it is working now.

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.