-
-
Notifications
You must be signed in to change notification settings - Fork 33.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
get return value of $emit event's callback #5443
Comments
This would be a breaking change. Just emit a callback. |
+1 |
An alternative would be to use a common pattern from Web APIs where you provide a method on the emitted event called something like For example: <component @click="callback">
</component>
function callback(evt) {
evt.waitUntil(new Promise(function(resolve, reject) {
setTimeout(() => {
resolve('resolved')
}, 2000)
}))
}
// in component
<script>
...
methods: {
handleClick(evt) {
var promise = Promise.resolve()
evt.waitUntil = p => promise = p
this.$emit('click', evt)
console.log(promise) // promise is a Promise
}
}
...
</script> If desired, you could get more robust and throw an error if |
Nice vision @dlongley, you see beyond to the edge!! |
You could also just pass the methods: {
handleClick(evt) {
var result = new Promise((resolve) => this.$emit('click', evt, resolve))
result.then((value) => console.log(value))
return result
}
} That way you're not mutating an object that you didn't create ;) The receiver would consume it as the second argument: function callback(evt, resolve) {
setTimeout(() => resolve('resolved'), 2000)
} |
This forces the receiver to call The |
@dlongley awesome approach that I had not thought of yet!
|
For those interested in @dlongley comment: https://developer.mozilla.org/en-US/docs/Web/API/ExtendableEvent/waitUntil |
I recently had an issue where I needed to do this in one of my event buses. I wrote a wrapper around the standard $emit using some ideas from this thread. It tidies up the API, and also allows only a single invocation of the promise per emit. Maybe not a 'best practice', but it is 'totally practical' AFAIAC... Here's a POC codepen: https://codepen.io/Flamenco/pen/deqPvy?editors=1111 /**
* Adds an promise-like object with resolve/reject methods as the last argument, and returns a promise.
* @param topic The topic to emit
* @param varargs A 0..n arguments to send to the receiver
* @return {Promise<any>} A promise with the result.
* The receiver must call resolve or reject on the final argument.
*/
Vue.prototype.$emit_p = function (topic, varargs) {
return new Promise((resolve, reject) => {
const arr = Array.from(arguments)
let invoked = false
const promiseLike = {
resolve: val => {
if (!invoked) {
invoked = true
resolve(val)
}
},
reject: val => {
if (!invoked) {
invoked = true
reject(val)
}
}
}
arr.push(promiseLike)
this.$emit.apply(this, arr)
});
} Publisher this.$emit_p('add', 1, 2).then(res=>console.log(res)) Subscriber this.$on('add', function(l,r,promise) {
setTimeout(()=>promise.resolve(l+r), 1000)
}) |
Could you pass the callback function as a prop instead of an event listener, then call the prop, e.g.: Parent: <template>
<v-child :callback="handleCallback" />
</template>
<script>
export default {
methods: {
handleCallback() {
return Promise.resolve();
}
}
}
</script> Child: props: {
callback: {
type: Function,
required: true,
},
},
methods: {
event() {
this.callback().then(() => {});
}
} This makes sense to me given event emitters are agnostic to who's listening, but this requires a return value |
@samboylett that works for component based events but I needed something for an event bus that is stored in Vuex so this won't work |
How to actually emit a callback? Examples from here doesn't work...
I have such situation. Sometimes
And I'm not sure why, but API calls are not in the order I need them to be:
where it actually should be:
|
…ou could also just pass the resolve parameter directly to $emit like so: methods: { handleClick(evt) { var result = new Promise((resolve) => this.$emit('click', evt, resolve)) result.then((value) => console.log(value)) return result } } That way you're not mutating an object that you didn't create ;) The receiver would consume it as the second argument: function callback(evt, resolve) { setTimeout(() => resolve('resolved'), 2000)
vuejs/vue#5443 참조 You could also just pass the resolve parameter directly to $emit like so:
Is there a chance this could be reconsidered today, when async/await code is much more commonly used than callbacks? It may be a breaking change, but I find it hard to imagine why any code needs to rely on emit returning the component itself. Also, it's pretty confusing that you can (and need to) specify the return type of handlers in typescript const emit = defineEmits<{
(event: 'click') : Promise<void> // would be nice to be able to use v-on:click="fetchData" in consuming components
}>();
const loading = ref(false);
onNativeButtonClick() {
loading.value = false;
await emit('click'); // VSCode says const emit: (event: "click") => Promise<void>, but actually returns component as stated in first post
loading.value = true;
} |
Version
2.2.6
Reproduction link
https://jsfiddle.net/50wL7mdz/27555/
Steps to reproduce
What is expected?
expect $emit get the return value of event's callback
What is actually happening?
get component self
The text was updated successfully, but these errors were encountered: