How to fetch data in Vue 3? - vue.js

I don't know how to fetch data with Vue 3? I created one action and with this action I am calling endpoint (https://api.openbrewerydb.org/breweries/5494). I didn't get response data.
Endpoint:
import { createStore } from 'vuex'
export default createStore({
state: {
},
mutations: {
},
actions: {
async getData() {
await fetch('https://api.openbrewerydb.org/breweries/5494', {
method: 'get',
headers: { 'Content-type': 'application/json' },
}).then((response) => {
if (!response.ok) {
throw Error(response.statusText);
}
console.log('response: ', response)
}).catch((error) => {
console.log('Looks like there was a problem: \n', error);
});
}
},
modules: {
}
})
Vue component:
<template>
<div #click="loadData">Load Data</div>
</template>
<script>
import { useStore } from 'vuex'
export default {
name: 'HelloWorld',
props: {
msg: String
},
setup () {
const store = useStore()
const loadData = () => {
store.dispatch('getData')
}
return { loadData }
}
}
</script>
As a response I didn't get anything but I should get:
{"id":5494,"name":"MadTree Brewing","brewery_type":"regional","street":"3301 Madison Rd","address_2":null,"address_3":null,"city":"Cincinnati","state":"Ohio","county_province":null,"postal_code":"45209-1132","country":"United States","longitude":"-84.4239715","latitude":"39.1563725","phone":"5138368733","website_url":"http://www.madtreebrewing.com","updated_at":"2018-08-24T15:44:22.281Z","created_at":"2018-07-24T01:34:01.620Z"}

You need to make the data to json
.then(res=>res.json())
this will do the trick for you.
const getData = () => {
fetch('https://api.openbrewerydb.org/breweries/5494', {
headers: { 'Content-type': 'application/json' },
}).then(res=>res.json()).then((response) => {
console.log({ response })
}).catch((error) => {
console.log('Looks like there was a problem: \n', error);
});
}
getData();
If the response fails, it will surely get you to catch.

This answer Should be the accepted answer.
If readers landed here while working through the introductory examples on the Vue.js website, Adarsh's code can be adapted thusly (for Vue.js 3):
<div id="beer">
{{ message }}
</div>
const Breweries = {
data() {
return {
message: ""
}},
mounted() {
fetch('https://api.openbrewerydb.org/breweries/', {
headers: { 'Content-type': 'application/json' },
}).then(res=>res.json()).then((response) => {
this.message = response;
}).catch( (error) => {
this.message = error;
});
}
}
Vue.createApp(Breweries).mount('#beer')

First you must install a package like axios
Then create an object from axios and call the API
import axios from "axios";
export default {
setup() {
function getUsers() {
axios.get("https://jsonplaceholder.typicode.com/users")
.then(function (response) {
// handle success
console.log(response.data);
})
.catch(function (error) {
// handle error
console.log(error);
});
getUsers();
}
return { getUsers };
},
};

Related

Problems with vuex: Uncaught (in promise) TypeError: _ctx.getProduct.image_url is undefined

I'm trying to load a product's data, passing props through the Vue Router, this is my code:
...store/modules/products_manager.js
import axios from 'axios';
const BASE_URL = "http://127.0.0.1:3000/"
const state = {
product: [],
products: [],
category: "",
}
const getters = {
getProducts(state) {
return state.products;
},
getProduct(state) {
console.log("GET")
console.log(state.product)
return state.product;
},
getCategory(state) {
return state.category;
},
}
const actions = {
getAllProducts({ commit }, payload) {
const config = {
params: {
title: payload['name']
}
}
new Promise((resolve, reject) => {
axios
.get(`${BASE_URL}products/`, config)
.then((response) => {
commit("setProducts", response);
resolve(response.data);
})
.catch((error) => {
reject(error);
});
});
},
getProductById({ commit }, payload) {
new Promise((resolve, reject) => {
axios
.get(`${BASE_URL}products/${payload}`)
.then((response) => {
commit("setProduct", response);
console.log("PRODUCT")
console.log(response.data)
resolve(response.data);
})
.catch((error) => {
reject(error);
});
});
},
getCategoryById({ commit }, payload) {
new Promise((resolve, reject) => {
axios
.get(`${BASE_URL}categories/${payload}`)
.then((response) => {
commit("setCategory", response);
resolve(response.data);
})
.catch((error) => {
reject(error);
});
});
},
}
const mutations = {
setProducts(state, data) {
state.products = data.data;
},
setProduct(state, data) {
console.log("SET")
console.log(data.data)
state.product = data.data;
},
setCategory(state, data) {
state.category = data.data;
},
}
export default {
state,
getters,
actions,
mutations,
}
../components/ProductPage.vue
<template lang="">
<div>
<p v-if="(getProduct != null || getProduct != undefined)" >{{ getProduct['image_url'][0] }}</p>
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex';
export default {
name: 'Product',
props: ["id", "category_id"],
computed: {
...mapGetters(["getProduct", "getCategory"]),
},
mounted() {
console.log(this.id)
console.log(this.category_id)
this.$store.dispatch("getProductById", this.id)
this.$store.dispatch("getCategoryById", this.category_id)
}
}
</script>
But I'm having some problems, I'm starting with vuex and I'm not understanding many things yet.
Error Printscreen
I did some tests, I used functions like created, updated, etc. With some of them, the information was even displayed on the screen, but it still generated the same errors. I believe it must be some error in the vue data flow, but I still don't understand how to solve it.
Sorry my bad english ;)
Solution:
<div>
<p v-if="(getProduct['image_url'] != null || getProduct['image_url'] != undefined)" >{{ getProduct['image_url'][0] }}</p>
</div>
Thank's #yoduh

How can I update the comments without refreshing it?

First, I'm using vuex and axios.
store: commentService.js
components:
CommentBox.vue (Top components)
CommentEnter.vue (Sub components)
This is the logic of the code I wrote.
In the store called commentService.js, there are mutations called commentUpdate.
And There are actions called postComment and getComment.
At this time, In the component called CommentBox dispatches getComment with async created().
Then, in getComment, commentUpdate is commited and executed.
CommentUpdate creates an array of comments inquired by getComment and stores them in a state called commentList.
Then I'll get a commentList with "computed".
CommentEnter, a sub-component, uses the commentList registered as compounded in the CommentBox as a prop.
The code below is commentService.js.
import axios from 'axios'
export default {
namespaced: true,
state: () => ({
comment:'',
commentList: []
}),
mutations: {
commentUpdate(state, payload) {
Object.keys(payload).forEach(key => {
state[key] = payload[key]
})
}
},
actions: {
postComment(state, payload) {
const {id} = payload
axios.post(`http://??.???.???.???:????/api/books/${id}/comments`, {
comment: this.state.comment,
starRate: this.state.starRate
}, {
headers: {
Authorization: `Bearer ` + localStorage.getItem('user-token')
}
})
.then((res) => {
console.log(res)
this.state.comment = ''
this.state.starRate = ''
)
.catch((err) => {
alert('댓글은 한 책당 한 번만 작성할 수 있습니다.')
console.log(err)
this.state.comment = ''
this.state.starRate = ''
})
},
async getComment({commit}, payload) {
const {id} = payload
axios.get(`http://??.???.???.???:????/api/books/${id}/comments`)
.then((res) => {
console.log(res)
const { comment } = res.data.commentMap
commit('commentUpdate', {
commentList: comment
})
})
.catch((err) => {
console.log(err)
commit('commentUpdate', {
commentList: {}
})
})
}
}
}
The code below is CommentBox.vue
computed: {
commentList() {
return this.$store.state.commentService.commentList
}
},
methods: {
async newComment() {
if(this.$store.state.loginService.UserInfoObj.id === '') {
alert('로그인 후 이용할 수 있습니다.')
return
}
this.$store.dispatch('commentService/postComment', {
id: this.$route.params.id,
comment: this.$store.state.comment,
starRate: this.$store.state.starRate
})
}
},
async created() {
this.$store.dispatch('commentService/getComment', {
id: this.$route.params.id
})
}
The code below is CommentEnter.vue
created() {
this.userComment = this.comment
},
props: {
comment: {
type: Object,
default: () => {}
}
},
I asked for a lot of advice.
There were many comments asking for an axios get request after the axios post request was successful.
In fact, I requested an axios get within .then() of the axios post, and the network tab confirmed that the get request occurred normally after the post request.
But it's still not seen immediately when I register a new comment.
I can only see new comments when I refresh it.
How can I make a new comment appear on the screen right away when I register it?
Can't you just call getComment when postComment is finished?
methods: {
async newComment() {
if(this.$store.state.loginService.UserInfoObj.id === '') {
alert('로그인 후 이용할 수 있습니다.')
return
}
this.$store.dispatch('commentService/postComment', {
id: this.$route.params.id,
comment: this.$store.state.comment,
starRate: this.$store.state.starRate
}).then(function() {
this.$store.dispatch('commentService/getComment', {
id: this.$route.params.id
})
})
}
},
}
Or since you're using async:
methods: {
async newComment() {
if(this.$store.state.loginService.UserInfoObj.id === '') {
alert('로그인 후 이용할 수 있습니다.')
return
}
await this.$store.dispatch('commentService/postComment', {
id: this.$route.params.id,
comment: this.$store.state.comment,
starRate: this.$store.state.starRate
})
this.$store.dispatch('commentService/getComment', {
id: this.$route.params.id
})
}
},
}

How to use $nuxt.$loading from axios interceptor

I would like to use $nuxt.$loading https://nuxtjs.org/api/configuration-loading/ outside of Vue component. I created central js for hitting APIs.
services/api-client.js
import axios from "axios";
import { state } from '../store/modules/sessions';
const axiosClient = axios.create({
baseURL: process.env.BASE_URL,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'X-Api-Key': state().token
}
});
axiosClient.interceptors.request.use(function (config) {
// show nuxt loading here
return config;
}, function (error) {
return Promise.reject(error);
});
axiosClient.interceptors.response.use(function (response) {
// hide nuxt loading here
if (response.data.status.code != 200) {
throw { message: response.data.status.errorDetail };
} else {
return response;
}
}, function (error) {
// hide nuxt loading here
return Promise.reject(error);
});
export default {
all(path) {
return axiosClient.get(path);
},
show(path) {
return this.all(path);
},
create(path, params) {
return axiosClient.post(path, params);
},
update(path, params) {
return axiosClient.put(path, params);
}
};
and from my index.vue I'm dispatching the actions which trigger the Api Request.
<template>
<div>
<h1> Welcome </h1>
</div>
</template>
<script>
export default {
created() {
this.$store.dispatch('getInsiders', this);
}
}
</script>
The solution to your problem is this code below.
Please try this.
export default function({ $axios, store }: any) {
$axios.onRequest((config: any) => {
store._vm.$nextTick(() => {
store._vm.$nuxt.$loading.start()
return config
})
})
$axios.onResponse((response: any) => {
store._vm.$nextTick(() => {
store._vm.$nuxt.$loading.finish()
return response
})
})
$axios.onError((error: any) => {
store._vm.$nextTick(() => {
store._vm.$nuxt.$loading.finish()
return Promise.reject(error)
})
})
}
Do you really need to declare own axios client?
Standard way how to do this is using nuxt's axios module and then customize it in your plugin.
nuxt.config.js
modules: ['#nuxtjs/axios'],
plugins: ['~/plugins/axios']
~/plugins/axios
export default ({ $axios, redirect }) => {
$axios.onError(error => {
// do anything you need
})
}
The axios module will manage loading status automatically.
Although you still can disable progress for individual requests
Eg from component/action
await this.$axios.$get('/myapi', { progress: false })

Why can't I pass my user_name value into my component? (Auth)

I am trying to pass the name of the user after authentication into a Vue component, but I get a name: undefined value after load.
Here is my AuthService.js:
//config details taken from OAUTH JS doc: https://github.com/andreassolberg/jso
import { JSO, Fetcher } from 'jso';
const client = new JSO({
providerID: '<my-provider>',
default_lifetime: 1800,
client_id: '<my-client-id>',
redirect_uri: 'http://localhost:8080/',
authorization:'<my-auth-server>/oauth/authorize'
//scopes: { request: ['https://www.googleapis.com/auth/userinfo.profile'] }
});
export default {
getProfile() {
// JSO plugin provides a simple wrapper around the fetch API to handle headers
let f = new Fetcher(client);
let url = 'https://www.googleapis.com/auth/userinfo.profile';
f.fetch(url, {})
.then(data => {
return data.json();
})
.then(data => {
return data.user_name;
})
.catch(err => {
console.error('Error from fetcher', err);
});
}
};
Then, in my single file component named MainNav, I have:
import AuthService from "#/AuthService";
export default {
name: "MainNav",
data() {
return {
name: ""
};
},
created() {
this.name = AuthService.getProfile();
}
};
</script>
Anyone have any tips on how I can get the user_name value from the AuthService to my component? I will then need to then display the name in my nav template. Doing a console.log test works fine, just can't return it to my SFC. Also, the JSO library is here: https://github.com/andreassolberg/jso#fetching-data-from-a-oauth-protected-endpoint
Because getProfile returns nothing (undefined). I see you use es6 then you can use async functions
//config details taken from OAUTH JS doc: https://github.com/andreassolberg/jso
import { JSO, Fetcher } from 'jso';
const client = new JSO({
providerID: '<my-provider>',
default_lifetime: 1800,
client_id: '<my-client-id>',
redirect_uri: 'http://localhost:8080/',
authorization:'<my-auth-server>/oauth/authorize'
//scopes: { request: ['https://www.googleapis.com/auth/userinfo.profile'] }
});
export default {
getProfile() {
// JSO plugin provides a simple wrapper around the fetch API to handle headers
let f = new Fetcher(client);
let url = 'https://www.googleapis.com/auth/userinfo.profile';
return f.fetch(url, {}) // return promise here
.then(data => {
return data.json();
})
.then(data => {
return data.user_name;
})
.catch(err => {
console.error('Error from fetcher', err);
});
}
};
And
import AuthService from "#/AuthService";
export default {
name: "MainNav",
data() {
return {
name: ""
};
},
async created() {
try {
this.name = await AuthService.getProfile();
} catch(error) {
// handle
}
}
};
</script>
Or without async (add one more then)
import AuthService from "#/AuthService";
export default {
name: "MainNav",
data() {
return {
name: ""
};
},
created() {
AuthService.getProfile().then((userName) => this.name = userName))
.catch((error) => { /* handle */ })
}
};
</script>

How to bind data from an api function into data object in vue.js

I am performing a Axios.get() to a Weather API, in result i want to filter specific data of information about "current weather" etc.
<template lang="html">
<div id="weather">
{{weatherData}}
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
weatherData: {
stringSummary: this.weatherApi.data.currently.summary,
},
};
},
created() {
this.weatherApi();
},
methods: {
async weatherApi() {
axios.get('https://api.darksky.net/forecast/
89cef1a2abe989e0d09a4ebd75f02452/53.551085,-9.993682?
lang=de&units=si')
.then((response) => {
console.log(response);
return response;
})
.catch((error) => {
console.log(error);
});
},
},
};
</script>
Please check my "stringSummary" part inside Data. Shouldn't this work?
I am thankful for any help.
You should assign weatherData in then block:
methods: {
async weatherApi() {
axios.get('https://api.darksky.net/forecast/
89cef1a2abe989e0d09a4ebd75f02452/53.551085,-9.993682?
lang=de&units=si')
.then((response) => {
this.weatherData = {
stringSummary: response.data.currently.summary
}
return response;
})
.catch((error) => {
console.log(error);
});
},