Home > Software engineering >  How to save Axios result in array to use in Vue.js v-for?
How to save Axios result in array to use in Vue.js v-for?

Time:10-28

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

CodePudding user response:

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

CodePudding user response:

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 >
    <Box v-for="title in newBox" :msg="title" :key="title" />
  </div>

  <RouterView />
</template>

CodePudding user response:

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!

CodePudding user response:

Thanks for all my mistake was ref and way of using it v-for...

  • Related