Let's say I have a button component that is imported in several other components. I want the child component to not be coupled to any one type of logic that happens when the button is clicked. So I want to hold that logic in the various components that leverage this button component.
I think there are at least 2 ways of going about this.
Have the child emit an event to the parents, and then let the parents define the handler.
Define the handlers in the parents and pass it down as props to the button component.
I'm used to doing the latter in React. Is there a best practice in vue for this situation?
Let's say I have a button component that is imported in several other components. I want the child component to not be coupled to any one type of logic that happens when the button is clicked. So I want to hold that logic in the various components that leverage this button component.
I think there are at least 2 ways of going about this.
Have the child emit an event to the parents, and then let the parents define the handler.
Define the handlers in the parents and pass it down as props to the button component.
I'm used to doing the latter in React. Is there a best practice in vue for this situation?
Share Improve this question asked May 25, 2018 at 15:11 Andrew KimAndrew Kim 3,3154 gold badges25 silver badges44 bronze badges6 Answers
Reset to default 37Vue.js events are callbacks, they are not DOM events. You can verify this, since you add a custom name to the event listener and not a DOM event name (
click
,focus
...), and there is noevent
object passed to the function, unless you specify an$event
argument in the$emit
call.
Events
Pros
- For libraries: keeps it lighter and clients have more flexibility on methods usage
- Helpful Vue devtools event logging
- Allow global listener (
this.$root.on
), although this can be better enhanced by Vuex.js. - Differentiated syntax:
:
for props and@
for events/methods
Cons
- Less explicit, harder to debug (fail silently if there are no listeners or the event name is misspelled)
Props
Pros
- More explicit, are declarative, can be defaulted, required, validated, what turns them easier to debug (runtime errors or compilation errors in TypeScript)
Cons
- Have to include props validation so you don't have to check if a
function()
prop exists before calling it (but using props validation is a good practice anyway...)
Conclusion
Looks like the approaches are more convention and personal preference over anything else, although I think that if it wasn't for the Vue.js documentation giving preference to the events approach, everybody would be gladly using props only, which in my opinion is better (clearer).
Props can do everything events do, except for a few cases (like $root
event listening pattern - noting Vuex.js replaces this feature and is preferred for scalability), with the advantage they are more explicit, debuggable and check-prone.
Summarized from: https://forum.vuejs.org/t/events-vs-callback-props/11451
The Vue philosophy is props down, events up. The first option follows that closer as the event itself is emitted (up) to the parent and then handled.
Also within a Vue SFC you have the added benefit of prefixing the bound attribute with a v-on (or @) which describes its intent as an event traveling up and not a v-bind (or :) which implies it's a prop even though its really a callback to an event.
As a newbie perspective migrated from React, I don't know why @event
even exists (or like the answers above - being the standard). I can't declare which events
a component would $emit
?, but I can easily see which props
are passed down. And by a good naming, I will be able to know which one is actually a callback event.
Best Practice
Best practice would be option number 1. You can see this practice being used in the official documentation: https://v2.vuejs.org/v2/guide/components.html#Sending-Messages-to-Parents-with-Events
Performance
As long as you pass a reference to a function to be executed when using the event bus or passing down as a prop, you should see almost no performance difference.
Example using option number 1
You can use this.$emit('eventName', dataToSend, ...)
to send the data to the parent component that would then listen on the component like this <my-component @eventName="yourHandler" />
. You would then be able to use different logic for each button.
I have created a fiddle for a multi-select component that implements this: https://jsfiddle.net/wkdL0xbc/
// HTML
<div id="app">
<multi-choice :items="myItems" @selected="alert($event)"></multi-choice>
<multi-choice :items="myItems" @selected="sayIsCool"></multi-choice>
</div>
// JavaScript
const multiChoice = {
template: '<div class="multi-choice"><span v-for="item in items" @click="select(item)">{{ item }}</span></div>',
props: ['items'],
methods: {
select(item) {
this.$emit('selected', item);
}
}
};
new Vue({
el: "#app",
data() {
return {
myItems: [
'Homer',
'Marge',
'Bart'
],
}
},
components: {
multiChoice: multiChoice
},
methods: {
sayIsCool(item) {
alert(item + ' is cool!')
}
}
})
You’re looking for “Transparent Wrappers”
Vue's customs event works different from a native DOM event. So you need to attach .native property to the event
But if you want the event to happen on the child, then you define a computed property that will return and an object of listeners. And now you won't
By default, attributes not defined as props will be added to the root element of the view
So you can set inheritAttrs: false and then bind the $attrs to the child and it then becomes the target for those attributes
Now you don't have to think about what the root component is.
Chris Fritz does a great job explaining how they work in his 7 secret patterns talk. Starts around 21:44 https://youtu.be/7lpemgMhi0k?t=21m44s
I think this depends if we don't give a better context. Consider props vs event is like pull vs push, quite similar to any pub-sub system.
When passing props, we inject (push) the dependencies of parent context to child context, and then child context can be polluted by parent context, not just holding the weak ref to the parent, any effect from a parent is now also executed within child context. This is also coupled between parent-child.
Consider event pulling, which parent is listening event from child, now every event data is preferably a copy value instead of ref, we don't have coupling issue between parent-child. In case we have event, we have also control by queue or custom modifier so that the usage from parent is easier to maintain (like we don't have to maintain debounce, throttle on parent context, but expect by event modifier, it should be done within child context, in this case is the Button component).
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1737091523a3921767.html
评论列表(0条)