I am fetching data from API inside the created method and i want to use these data in the page.
Here is my code.
created(){
let id = this.$route.params.id
let videos;
this.$axios.get(this.$axios.defaults.apiURL + 'v1.0.0/tips/' +id,).then((response) => {
this.videos = response.data.data;
}, (error) => {
toast.$toast.error('Something went wrong! Please try again', {
position: 'top'
})
});
},
data(){
let videos = this.videos;
return {
video: {
sources: [{
src: videos.video_url,
type: 'video/mp4'
}],
options: {
autoplay: true,
volume: 0.6,
poster: videos.thumbnail
}
}
}
}
I am getting error that thumbnail and video_url is not defined. This 2 values are coming from API response. How can i solve this? Thanks
I can see two obvious issues with your code (without seeing it in action):
created is a synchronous hook, but your axios request is returning a promise. Instead of waiting for the promise, you are immediately trying to show the result, hence the issue you are encountering - the data just hasn't arrived yet.
Your use of this seems a bit chaotic (i.e. let videos = this.videos - where would this.videos come from? The only other 'videos' is declared inside of a different function with let)
There are multiple ways to solve this, depending on what you want to show while you are fetching the data and what type of component this is - if you want to show a spinner while you are waiting for the request to be answered, or if you just want to show some progress bar on the previous page and only enter this one once it's loaded.
In-component loading
In the first case, I would suggest setting a variable or using a loader management solution like vue-wait. Your code could look like this then:
data() {
return {
loading: true,
videos: null,
}
},
computed: {
video() {
return this.videos ? {
sources: [{
src: this.videos.video_url,
type: 'video/mp4'
}],
options: {
autoplay: true,
volume: 0.6,
poster: this.videos.thumbnail
}
} : null
}
},
methods: {
fetch() {
let id = this.$route.params.id
this.$axios.get(this.$axios.defaults.apiURL + 'v1.0.0/tips/' + id, ).then((response) => {
this.videos = response.data.data;
}, (error) => {
toast.$toast.error('Something went wrong! Please try again', {
position: 'top'
})
}).finally(() => (this.loading = false));
},
},
created() {
this.fetch()
},
In your template, you would add somewhere v-if=!loading to make sure that the request has finished before you try to show something
Data-fetching before entering page
If this is a page though, you could request the data in beforeRouteEnter - there's a whole article that explains the principle on the vue site
Related
Today I came across an unexpected situation that I could solve, but I would like to understand what's happening.
I have a form for which I use a watcher to track any changes (deep).
If there are changes, another variable is set to true (so the form is dirty).
Typical use case where you warn users that they haven't saved their entries before they move away.
data() {
return {
formWatcher: null,
dirty: false,
form: {
id: '',
title: '',
content: '',
created_at: '',
updated_at: ''
}
}
},
...
watchForm() {
this.formWatcher = this.$watch('form', () => this.dirty = true, {deep: true})
},
unwatchForm() {
this.dirty = false
this.formWatcher()
},
...
async created() {
this.setData(...)
this.assignForm()
this.watchForm() // starts watching the form
},
So far, that works as expected.
If a user now saves his work by pressing the "update" button, We hit the server with a PUT, get the response, update the updated_at field (which is part of the form variable) and then we set dirty to false, avoiding further database calls.
First, my approach looked simple:
async update() {
let response = await axios.put(`/legals/${this.id}`, this.form)
let { updated_at } = response.data.data
this.form.updated_at = updated_at // this set dirty immediately to true
this.dirty = false // doesn't work, dirty is set immediately to true again
},
However, that didn't work - after the update, the dirty variable was immediately set to true again, because of this line:
this.form.updated_at = updated_at
Which lead me to the assumption that
this.dirty = false
runs before or asynchronous with
this.form.updated_at = updated_at
I then wrapped everything in the good old axios().then().then() way, and it worked as expected.
So finally I came up with this approach which worked as expected:
async update() {
let response = await axios.put(`/legals/${this.id}`, this.form)
let { updated_at } = response.data.data
await this.setFormAttribute('updated_at', updated_at)
await this.setDirty(false)
},
...
setFormAttribute(key, value) {
this.form[key] = value
},
setDirty(value) {
this.dirty = false
},
As you can see, I set the values now in setters functions, for which I "wait".
So, this works now exactly as I wanted, but I don't really understand why the naive approach didn't work.
I expected that if I wait for the response of axios in an async/await function, then assigning the respective variables would be synchronous, which however was not the case.
Can someone explain what's exactly going on here?
I have two react queries in the same component
const { data: sdrData, status: sdrDataLoading } = useQuery(
[queryInfo[0]?.dcsSysId, data[0]?.dcsStructSysId, data[cardIndex]?.dcsStructNodeId],
() => getSDR(queryInfo[0]?.dcsSysId, data[0]?.dcsStructSysId, data[cardIndex]?.dcsStructNodeId),
);
const { isIdle, data: sdrTemplateData, status: sdrTemplateDataLoading } = useQuery(
[sdrData[0]?.dcsSdrSysId, queryInfo[0]?.fldTemplateSysId],
() =>
SDRTemplateValues(sdrData[0]?.dcsSdrSysId, queryInfo[0]?.fldTemplateSysId, {
// The query will not execute until the userId exists
enabled: !!sdrData[0]?.dcsSdrSysId,
retry: true,
}),
);
My second query is depended on the first I need to access sdrData[0] for the first arg in my query however when I do this the query is undefined initially and it fails. Is there a good way to handle this. I saw you can set it equal to a variable, but I'm still faced with the same problem.
I need a way to tell the first query to wait until the second query is finished before it tried to access the arguments. I thought you could set enabled like I did, but that didn't work either.
I was able to solve this by adding the data parameter I need to the beginning of the argument array like this.
const { data: sdrData, status: sdrDataLoading } = useQuery(
queryInfo[0]?.dcsSysId && [
queryInfo[0]?.dcsSysId,
data[0]?.dcsStructSysId,
data[cardIndex]?.dcsStructNodeId,
],
() => getSDR(queryInfo[0]?.dcsSysId, data[0]?.dcsStructSysId, data[cardIndex]?.dcsStructNodeId),
);
const { data: sdrTemplateData, status: sdrTemplateDataLoading } = useQuery(
sdrData?.[0]?.dcsSdrSysId && [sdrData?.[0]?.dcsSdrSysId, queryInfo[0]?.fldTemplateSysId],
() => SDRTemplateValues(sdrData?.[0]?.dcsSdrSysId, queryInfo[0]?.fldTemplateSysId),
);
You are on the right path here.
You just need to check if sdrData is undefined. You are trying to access the first element (sdrData[0]) but initially it's undefined.
...
{
enabled: !!(sdrData && sdrData[0]?.dcsSdrSysId
}
...
So I have this state for handling error messages and that state have two actions
The first one for setting the message:
export const setNotification = (message) => {
return {
type: "SET_NOTIFICATION",
data: {
message,
visibility: "visible"
}
}
}
And the second for removing the message after 5 seconds:
export const clearNotification = (seconds=5) => {
setTimeout(()=> { return {
type: "REMOVE_NOTIFICATION",
data: {
message: "",
visibility: "hidden"
}
}}, seconds * 1000)
}
And when calling the second function called ClearNotification I get this error:
Error: Actions must be plain objects. Use custom middleware for async actions.
Why am I getting this message and how can I fix it?
Thanks.
That's because you can not return a function as action. The actions are simple objects of the shape ´{type: string, ...any}´. If you want to return a function you should google for redux-thunk or something like redux-saga or redux-observable but those are quite tricky.
This link has an example of what you want to do. https://github.com/reduxjs/redux-thunk#motivation
I don't know why but I have some problems with my Dashboard.
So basically I want to create some fancy Donut Charts.
For that I've prepared a dataset-Array where I put my numbers in. All that works.
But when I get my data from the database I want to change the array, to update the Chart.
This is where I have problems.
So my data() looks like this:
data() {
return {
disturbances_category_0: [],
disturbances_category_1: [],
disturbances_category_2: [],
disturbances_category_3: [],
datasets: [
{
data: [20, 20, 10, 50], //HERE I HAVE TO CHANGE THE NUMBERS <-------------
backgroundColor: ["#A40000", "#580000", "#EC4A3B", "#179C7D"],
hoverBackgroundColor: ["#ff1a1a", "#b30000", "#f4948b", "#66bfac"]
}
],
labels: ["Banana", "Apple", "Strawberry", "Cherry"],
option: {}
};
},
And then there is my created()-Block, where I use Axios + Sequelize and Feathers to get my data:
created() {
axios.get('http://localhost:3030/disruptions/', {
params: {
DisruptionCategory: 0
}
})
.then((response) => {
this.disturbances_category_0 = response.data.data; //HERE IS THE COMPLETE ARRAY
this.datasets[0].data[0] = this.disturbances_category_0.length; //HERE I WANT TO SET THE LENGTH
})
.catch((error) => {
console.log(error.data);
});
//imagine that for the other fruits as well...
console.log(this.datasets[0].data[0]);
}
If I test this script I always get "20" as printout.
I don't know why it doesn't change the datasets.data-Array ... I also tried out to use Array.push but... nothing happened..
I'm sure I forgot something obvious...
It is because the console log likely happened long before your then block executed. Its initial value is an array of four integers before you overwrite it with a length. Try making the created function async and await the axios promise chain to resolve.
async function created() {
await axios.get('http://localhost:3030/disruptions/', { // await the resolve
params: {
DisruptionCategory: 0
}
})
.then((response) => {
this.disturbances_category_0 = response.data.data; //HERE IS THE COMPLETE ARRAY
this.datasets[0].data[0] = this.disturbances_category_0.length; //HERE I WANT TO SET THE LENGTH
})
.catch((error) => {
console.log(error.data);
});
//imagine that for the other fruits as well...
console.log(this.datasets[0].data[0]); // now this should be updated
}
console.log(this.datasets[0].data[0]);
The above will run before the response to your request has been handled since it is asynchronous. Your code will just keep executing while the .then() part will execute on another thread once you get a response from the server.
I'm using React v 16.3.2 and am building an app to communicate orders with a DB on Firebase, also using axios 0.18.0.
I'm expecting that once I hit a certain button (continue) it will create this spinner effect on the screen as it loads, so I have the following code:
purchaseContinueHandler = () => {
this.setState = ({loading: true});
const order = {
ingredients: this.state.ingredients,
price: this.state.totalPrice,
customer: {
name: 'Name',
address: {
street: 'teststreet 1',
zipCode: '86753',
country: 'U.S.'
},
email: 'example#example.com'
},
deliveryMethod: 'fastest'
}
axios.post('/orders.json', order)
.then(response => { this.setState( { loading: false } );
})
.catch(error => {
this.setState( { loading: false } ); //**<--This is where i get the error**
});
}
I run it and hit Continue on the app and get the error:
Unhandled Rejection (TypeError): _this.setState is not a function
and it points to the line listed above.
Ran into this documentation and tried to implement the solution that worked for him (create a constructor() and bind this to this) but that didn't work.
I was reading that this was no longer automatically added to the function but not sure what to do with that information, I'm pretty new to React still.
Any advice?
You are assigning an object to setState in the first line of code, so when you try to call it later it no longer is a function...
this.setState = ({loading: true});
should be
this.setState({loading: true})
The setState is a function, you change it to an JavaScript Object, I guess it's a tiny mistake, you have to write:
this.setState({loading: true})
Use it not change it to other things.