Skip to content

Add various improvements to the Events API migration guide #1124

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

Merged
merged 1 commit into from
Jul 7, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 40 additions & 19 deletions src/guide/migration/events-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,77 +7,98 @@ badges:

## Overview

`$on`, `$off` and `$once` instance methods are removed. Application instances no longer implement the event emitter interface.
`$on`, `$off` and `$once` instance methods are removed. Component instances no longer implement the event emitter interface.

## 2.x Syntax

In 2.x, Vue instance could be used to trigger handlers attached imperatively via the event emitter API (`$on`, `$off` and `$once`). This was used to create _event hubs_ to create global event listeners used across the whole application:
In 2.x, a Vue instance could be used to trigger handlers attached imperatively via the event emitter API (`$on`, `$off` and `$once`). This could be used to create an _event bus_ to create global event listeners used across the whole application:

```js
// eventHub.js
// eventBus.js

const eventHub = new Vue()
const eventBus = new Vue()

export default eventHub
export default eventBus
```

```js
// ChildComponent.vue
import eventHub from './eventHub'
import eventBus from './eventBus'

export default {
mounted() {
// adding eventHub listener
eventHub.$on('custom-event', () => {
// adding eventBus listener
eventBus.$on('custom-event', () => {
console.log('Custom event triggered!')
})
},
beforeDestroy() {
// removing eventHub listener
eventHub.$off('custom-event')
// removing eventBus listener
eventBus.$off('custom-event')
}
}
```

```js
// ParentComponent.vue
import eventHub from './eventHub'
import eventBus from './eventBus'

export default {
methods: {
callGlobalCustomEvent() {
eventHub.$emit('custom-event') // if ChildComponent is mounted, we will have a message in the console
eventBus.$emit('custom-event') // if ChildComponent is mounted, we will have a message in the console
}
}
}
```

## 3.x Update

We removed `$on`, `$off` and `$once` methods from the instance completely. `$emit` is still a part of the existing API as it's used to trigger event handlers declaratively attached by a parent component
We removed `$on`, `$off` and `$once` methods from the instance completely. `$emit` is still a part of the existing API as it's used to trigger event handlers declaratively attached by a parent component.

## Migration Strategy

In Vue 3, it is no longer possible to use these APIs to listen to a component's own emitted events from within a component, there is no migration path for that use case.
[Migration build flag: `INSTANCE_EVENT_EMITTER`](migration-build.html#compat-configuration)

In Vue 3, it is no longer possible to use these APIs to listen to a component's own emitted events from within a component. There is no migration path for that use case.

### Root Component Events

Static event listeners can be added to the root component by passing them as props to `createApp`:

```js
createApp(App, {
// Listen for the 'expand' event
onExpand() {
console.log('expand')
}
})
```

But the eventHub pattern can be replaced by using an external library implementing the event emitter interface, for example [mitt](https://github.com/developit/mitt) or [tiny-emitter](https://github.com/scottcorgan/tiny-emitter).
### Event Bus

The event bus pattern can be replaced by using an external library implementing the event emitter interface, for example [mitt](https://github.com/developit/mitt) or [tiny-emitter](https://github.com/scottcorgan/tiny-emitter).

Example:

```js
//eventHub.js
// eventBus.js
import emitter from 'tiny-emitter/instance'

export default {
$on: (...args) => emitter.on(...args),
$once: (...args) => emitter.once(...args),
$off: (...args) => emitter.off(...args),
$emit: (...args) => emitter.emit(...args),
$emit: (...args) => emitter.emit(...args)
}
```

This provides the same event emitter API as in Vue 2.

These methods may also be supported in a future compatibility build of Vue 3.
In most circumstances, using a global event bus for communicating between components is discouraged. While it is often the simplest solution in the short term, it almost invariably proves to be a maintenance headache in the long term. Depending on the circumstances, there are various alternatives to using an event bus:

[Migration build flag: `INSTANCE_EVENT_EMITTER`](migration-build.html#compat-configuration)
* [Props](/guide/component-basics.html#passing-data-to-child-components-with-props) and [events](/guide/component-basics.html#listening-to-child-components-events) should be your first choice for parent-child communication. Siblings can communicate via their parent.
* [Provide and inject](/guide/component-provide-inject.html) allow a component to communicate with its slot contents. This is useful for tightly-coupled components that are always used together.
* `provide`/`inject` can also be used for long-distance communication between components. It can help to avoid 'prop drilling', where props need to be passed down through many levels of components that don't need those props themselves.
* Prop drilling can also be avoided by refactoring to use slots. If an interim component doesn't need the props then it might indicate a problem with separation of concerns. Introducing a slot in that component allows the parent to create the content directly, so that props can be passed without the interim component needing to get involved.
* [Global state management](/guide/state-management.html), such as [Vuex](https://next.vuex.vuejs.org/).