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
asconst newBox = ref([])
- Use
newBox
asnewBox.value
instead ofthis.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
inscript setup
, you can pretty much act as if it is a regular JS script. - Prefer
let
andconst
overvar
. Forref
s useconst
, 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...