I am utilizing a payment component that uses a callback function to show whether or not the payment was successful I am trying to execute a function in that callback method that tells the backend that payment was complete with some details.
Sample of component
<component
:amount="amount"
:ref="ref"
:callback="processPayment"
:close="close"
>Proceed to payment</component>
Payment callback method
processPayment: res => {
//window.alert("Payment recieved");
this.postPayment(res); // <-- this does not execute.
}
Any ideas how I could get it to work ?
This is an issue with this.
this in arrow function does not refer to the owner of the function, rather arrow function takes this from it's context, which will not be the Vue instance
So, avoid using arrow functions as Main methods in Vue component. You can use arrow function as callback.
processPaymentfunction(res){
//window.alert("Payment recieved");
this.postPayment(res); // <-- this will execute.
}
Related
I am quite new to Vue.js and while developing my first project i have stumbled upon a problem which I think is related to the component's lifecycle.
The context is the following:
I am using Vue 3 with composition API.
I have a "Map" component in which I use d3.js to show a chart.
In my Setup() method I have onBeforeMount() and onMounted().
In onBeforeMount() method, I want to use data from my Firestore database for the values in the chart. The console.log on line 47 shows the data correctly.
In onMounted(), is where I plan to put my d3 chart. But when I try to access the data as in console.log on line 55, I get undefined...
Ideally, from "Map" component, I want to fetch the data from my database and use it in order to create the chart and then have the component render the chart.
Then I would have another component called 'MapSettings" that will be able to alter the data in "Map" such as filters etc...and have the values automatically updated in the chart.
Finally, both components will be siblings and have same parent component. So "Map" and "MapSettings" are on same hierarchical level.
But first I need to understand why I am getting undefined.. Any help or suggestion would be greatly appreciated!
Your lifecycle hooks look nice. The problem that you're facing has to do with code been executed asynchronously and code been executed synchronously.
You're declaring a function that uses async-await feature. This function will be executed asynchronously. In this case, you're getting data from Firestore and storing it in a ref at onBeforeMount().
On the other hand, you're declaring a normal function at onMounted() trying to access a ref's value, which will result in undefined because the function that you define at onBeforeMount() didn't finish its execution (or it's in the event queue) when onMounted is called.
That's why you first see the console.log that comes from onMounted.
One solution would merge both functions in one lifecycle hooks and use async await:
setup() {
const {actorDocs, load} = getActorDocs()
const actorsData = red([])
// load actor data from db
onBeforeMount( async () => {
await load()
actorsData.value = actorDocs
console.log(actorsData.value)
// manipulate it here...
})
}
Keep in mind that you cannot pause with async-await a lifecycle hook. What you're pausing is the function that Vue will execute in that hook. Indeed, this is really nice because pausing a hook wouldn't be efficient at all.
i face that problem, in my case i want use imgsRef.value out of onBeforeMount scope. How to get imgsRef value out of beforeMount scope?
onBeforeMount( async () => {
await axios
.get("http://localhost:3000/ourMoment")
.then((response) => {
imgsRef.value = response.data
// imhsRef get the value from api
console.log(imgsRef.value.photo)
})
})
// i try to concole.log here but the value still empty
console.log(imgsRef.value)
I'm using the Context API and React functional components with hooks. I have a functional component ProfileForm.js
At the top of this file I call useContext so I can get access to the current state (an array of profile objects).
const {state: {userProfiles}, addProfile, removeProfile, editProfile} = useContext(UserProfilesContext);
For this example I will focus on the function addProfile. When the user clicks the submit button, I want to add the new profile to the global state/context and I want to save the updated list to AsyncStorage.
Here is my handler:
const saveProfileHandler = async(profiles) = >
{
const {
firstName, lastName, userPhone, userEmail, userMonth, userDay, userYear,
userStreet, userCity, userState, userZip,
}
= formState.inputValues;
Keyboard.dismiss();
if (validateForm()) {
let month = userMonth;
let day = userDay;
if (month.length == = 1) {
month = `0 $ { userMonth }
`;
}
if (day.length == = 1) {
day = `0 $ { userDay }
`;
}
const profile = new UserProfile(
firstName.trim(),
lastName.trim(),
userPhone.trim(),
userEmail.trim(),
month.trim(),
day.trim(),
userYear.trim(),
userStreet.trim(),
userCity.trim(),
userState.trim(),
userZip.trim(), );
// add profile to Context object
addProfile(profile);
await saveUserProfilesToStorage([... profiles, profile ]);
navigation.pop();
}
};
When I call addProfile I update the global state/context, so I know that React will re-render my component. So, I have 2 questions really:
Is it unsafe to rely on the global state value that I just saved. I mean, can I use the updated context state and save that to AsyncStorage or will it not be updated yet and thus unreliable?
After I call addProfile does the rest of the function continue to run before re-rendering from the state update, or does addProfile cause the component to re-render before the rest of the function finishes? If it does re-render in the middle of the function call, when does the rest of the function execute?
Thanks in advance.
This is what I was able to learn. I'll put it up here for others that stumble upon it.
It is important to know that in React, setState() is an asynchronous function. The JavaScript engine is made up of the memory heap and the call stack. The call stack will run all synchronous functions. Along side the JavaScript engine are the Web APIs (provided by the browser) and an Event Loop (callback queue).
When a function is executed it is placed on the call stack and execution begins synchronously. If you call another function from inside the currently running function, the new function will get its own execution context. The current function will pause execution, the new function will execute to completion (assuming no new function calls inside its context) and return control to the first function which will continue execution.
Asynchronous Events
Asynchronous code runs within the Web APIs environment of the browser. This prevents the code from blocking the JavaScript thread/call stack. Callback functions for the asynchronous code are registered in the Web APIs environment. When the callback is ready to be executed it is placed in the callback queue. All callbacks, except those returned by promises, are queued up here.
The callbacks won't be executed until the call stack is empty. Then they will be executed in a FIFO (first in first out) order.
It is also important to know that callbacks from promises (then, catch) don't get put into the callback queue. They go into a micro tasks queue. This queue has priority over the callback queue. This means all of the callbacks from the micro tasks queue will be called before the callback queue's tasks.
In my case, the context update will occur after navigation.pop(); but since the context is global and I'm not updating the UI after the component has unmounted it should be okay.
If I'm wrong on anything I welcome corrections.
According to the page on event handling in the docs for Vue, when you use v-on like v-on:click="handler" the handler function will automatically get the original DOM event as the first argument. This code snippet is directly adapted from those docs.
new Vue({
// Vue config shortened for brevity
methods: {
handler(event) {
// `this` inside methods points to the Vue instance
alert('Hello ' + this.name + '!')
// `event` is the native DOM event
if (event) {
alert(event.target.tagName)
}
}
}
})
Why the heck can I still access event even if I omit it from the functions parameter list like this:
handler() {
console.log(event); // Still returns the native DOM object even though
// I don't explicitly define `event` anywhere
}
Shouldn't event be undefined if I don't add it as an argument to the function?
I believe that'll be the global window.event:
https://developer.mozilla.org/en-US/docs/Web/API/Window/event
Nothing to do with Vue, it's just an unfortunate coincidence that you happened to call it event.
Maybe the docs explains the reason to use event in the handler function as first argument:
You should avoid using this property in new code, and should instead use the Event passed into the event handler function.
https://developer.mozilla.org/en-US/docs/Web/API/Window/event
I'm working on an app in React Native, and am having trouble accessing props that I feed into a component I made.
If I do console.log(this.props) within the constructor, I can see the props display in the console as desired, however if I put it in any other method, it prints undefined. How can I access the props that are clearly being sent to the component from outside of the constructor method?
You are probably adding new methods that are not binding this.
Check if you are writing the method like this:
myMethod(){
//Code
}
and just change it to:
myMethod = () => {
//Code
}
Edit: Like #Li357 says, these are called arrow functions. Arrow functions don't bind this automatically, and as a consequence receive the this of the surrounding class. In your case it will solve your issue as you want to access the properties of that class but you might want to read about it and how binding works in JS classes.
Another option is to write function.bind() but either way should work.
In the Vue app , it could add the event listener that is called one time by using vm.$once.
For example, in the child component of Vue App, it could emit the event using vm.$emit('myEvent', data). emit event
And then it could be processed by adding the event listener to this event using vm.$once in the Vue app.
At this time, I want to pass the additional data to event handler.
I've tried as following. But it throws an error.
Uncaught ReferenceError: $event is not defined
//In the Vueapp
this.$refs.child.$once(
'myEvent', this.eventHandler($event, additional_data)
);
But I think that it could pass the additional data when using v-on.
<child-component ref="child" v-on:myEvent="eventHandler($event, additional_data)"></child-component>
//$event is the data emitted from the event , "myEvent".
When using vm.$once or vm.$on, couldn't it pass the additional parameter?
Note: the reason that I use vm.$once is that I want to execute the eventHandler only one time when emitting the custom event, myEvent and add it dynamically .
You need to capture the arguments passed into the event handler. You can do this by using an anonymous function for the handler that calls your method. For example
this.$refs.child.$once('myEvent', $event => {
this.eventHandler($event, additional_data)
})
You could also get fancy with Function.prototype.bind() however you would have to reverse the arguments list as bind prepends arguments.
For example
methods: {
eventHandler(data, $event) { // reversed argument list
// etc
}
}
and
this.$refs.child.$once('myEvent', this.eventHandler.bind(this, additional_data))