This is a live document. Last update: 08/17/2016 as of 2.0.0-rc.2
General Notes
- A checked item means it has been implemented in the 2.0 development branch.
- Features subject to change during development.
- The breaking change list is not guaranteed to be complete during development.
- There are some upgrade tips at the end.
High Level Changes
- The template parser no longer relies on the DOM (unless you are using the real DOM as your template), so as long as you are using string templates (
<script type="text/x-template">, inline JavaScript strings, or compiled via single-file components), you are no longer subject to any of the template parsing limitations in 1.x. However, if you are relying on mounting to an element with existing content as template (using the el option), you will still be subject to those limitations.
- The compiler (the part which converts a template string to a render function) and the runtime can now be separated. There will be two different builds:
- Standalone build: includes both the compiler and the runtime. This functions basically exactly the same Vue 1.x does.
- Runtime only build: since it doesn't include the compiler, you need to either pre-compiled templates in a compile step, or manually written render functions. The npm package will export this build by default, since when consuming Vue from npm, you will likely be using a compilation step (with Browserify or Webpack), during which
vueify or vue-loader will perform the template pre-compilation.
Global config
Global API
Options
data
DOM
Lifecycle Hooks
Assets
Misc
Instance Properties
Instance Methods
data
events
DOM
Lifecycle
Directives
Special Components
Special Attributes
Server-side Rendering
Other Breaking Changes
v-for iteration syntax change
-
Deprecating $index and $key
Both of these are being deprecated in favor of more explicit named indices and keys. This syntax is a bit magical and has limitations in nested loops. As a bonus, there will be two fewer points of syntax for newcomers to learn.
-
New array syntax
value in arr
(value, index) in arr (switched order of arguments to be more consistent with JavaScript's forEach and map)
-
New object syntax
value in obj
(value, key) in obj (switched order of arguments, partly to be more consistent with many common object iterators, such as lodash's)
(value, key, index) in obj (index will now be available in object iteration for visual purposes, such as table striping)
Directive interface change
In general, in 2.0 directives have a greatly reduced scope of responsibility: they are now only used for applying low-level direct DOM manipulations. In most cases, you should prefer using Components as the main code-reuse abstraction.
Directives no longer have instances - this means there's no more this inside directive hooks and bind, update and unbind now receives everything as arguments.
Note the binding object is immutable, setting binding.value will have no effect, and properties added to it will not be persisted. You can persist directive state on el if you absolutely need to:
<div v-example:arg.modifier="a.b"></div>
// example directive
export default {
bind (el, binding, vnode) {
// the binding object exposes value, oldValue, expression, arg and modifiers.
binding.expression // "a.b"
binding.arg // "arg"
binding.modifiers // { modifier: true }
// the context Vue instance can be accessed as vnode.context.
},
// update has a few changes, see below
update (el, binding, vnode, oldVnode) { ... },
// componentUpdated is a new hook that is called AFTER the entire component
// has completed the current update cycle. This means all the DOM would
// be in updated state when this hook is called. Also, this hook is always
// called regardless of whether this directive's value has changed or not.
componentUpdated (el, binding, vnode, oldVNode) { ... },
unbind (el, binding, vnode) { ... }
}
You can use destructuring if you only care about the value:
export default {
bind (el, { value }) {
// ...
}
}
In addition, the update hook has a few changes:
- It no longer gets called automatically after
bind.
- It now always gets calls when the component is re-rendered, regardless of whether the value it's bound to has changed or not. You can compare
binding.value === binding.oldValue to skip unnecessary updates, but there are also cases where you'd want to always apply updates, e.g. when the directive is bound to an Object that might have been mutated instead of replaced.
elementDirective, directive params and directive options such as acceptStatement, deep etc. are all deprecated.
Filter Usage and Syntax Change
In Vue 2.0, there are several changes to the filter system:
-
Filters can now only be used inside text interpolations ({{}} tags). In the past we've found using filters with directives such as v-model, v-on etc. led to more complexity than convenience, and for list filtering on v-for it is more appropriate to move that logic into JavaScript as computed properties.
-
Vue 2.0 will not ship with any built-in filters. It is recommended to use standalone libraries dedicated for solving problems in a specific domain, e.g. moment.js for formatting dates and accounting.js for formatting financial currencies. You are also welcome to create your own filter pack and share it with the community!
-
The filter syntax has changed to be more inline with JavaScript function invocation, instead of taking space-delimited arguments:
{{ date | formatDate('YY-MM-DD') }}
Transition System
Transition CSS class changes:
The always-on v-transition class is no longer added and Vue now uses the same classes Angular and React CSSTransitionGroup does:
-
v-enter: applied before element is inserted, remove after 1 tick. (starting state for enter)
-
v-enter-active: applied before element is inserted, removed when transition/animation finishes. (active + ending state for enter)
-
v-leave: applied right when the leave transition is triggered, remove after 1 tick (starting state for leave)
-
v-leave-active: applied right when the leave transition is triggered, removed when the transition/animation finishes. (active + ending state for leave)
v-enter-active and v-leave-active gives you the ability to specify different easing curves for enter/leave transitions. In most cases, upgrading means simply replacing your current v-leavewith v-leave-active. (For CSS animations, use v-enter-active + v-leave-active)
Transition API Change
-
The <transition> component
All single-element transition effects are now applied by wrapping the target element/component with the <transition> built-in component. This is an abstract component, which means it does not render an extra DOM element, nor does it show up in the inspected component hierarchy. It simply applies the transition behavior to the wrapped content inside.
The simplest usage example:
<transition>
<div v-if="ok">toggled content</div>
</transition>
The component defines a number of props and events that maps directly to the old transition definition options:
Props
-
name: String
Used to automatically generate transition CSS class names. e.g. name: 'fade' will auto expand to .fade-enter, .fade-enter-active, etc. Defaults to "v".
-
appear: Boolean
Whether to apply transition on initial render. Defaults to false.
-
css: Boolean
Whether to apply CSS transition classes. Defaults to true. If set to false, will only trigger JavaScript hooks registered via component events.
-
type: String
Specify the type of transition events to wait for to determine transition end timing. Available values are "transition" and "animation". By default, it will automatically detect the type that has a longer duration.
-
mode: String
Controls the timing sequence of leaving/entering transitions. Available modes are "out-in" and "in-out"; defaults to simultaneous.
-
enterClass, leaveClass, enterActiveClass, leaveActiveClass, appearClass, appearActiveClass: String
Individually configure transition CSS classes.
Example applying transition to dynamic components:
<transition name="fade" mode="out-in" appear>
<component :is="view"></component>
</transition>
Events
Corresponds to the JavaScript hooks available in 1.x API.
- before-enter
- enter
- after-enter
- before-leave
- leave
- after-leave
- before-appear
- appear
- after-appear
Example:
<transition @after-enter="transitionComplete">
<div v-show="ok">toggled content</div>
</transition>
When the entering transition completes, the component's transitionComplete method will be called with the transitioned DOM element as the argument.
Some notes:
leave-cancelled is no longer available for insertion/removals. Once a leave transition starts, it cannot be cancelled. It is, however, still available for v-show transitions.
- Similar to 1.0, for
enter and leave hooks, the presence of cb as the second argument indicates the user wants explicit control of the ending timing of the transition.
-
The <transition-group> component
All multi-element transition effects are now applied by wrapping the elements with the <transition-group> built-in component. It exposes the same props and events as <transition> does. The difference being that:
- Unlike
<transition>, <transition-group> renders a real DOM element. By default it renders a <span>, and you can configure what element is should render via the tag prop. You can also use it with the is attribute, e.g. <ul is="transition-group">.
<transition-group> does not support the mode prop.
- Every child in a
<transition-group> must be uniquely keyed.
Example:
<transition-group tag="ul" name="slide">
<li v-for="item in items" :key="item.id">
{{ item.text }}
</li>
</transition-group>
Moving Transitions
<transition-group> supports moving transitions via CSS transform. When a child's position on screen has changed after an updated, it will get applied a moving CSS class (auto generated from the name prop or configured with the moveClass prop). If the CSS transform property is "transition-able" when the moving class is applied, the element will be smoothly animated to its destination using the FLIP technique.
See a live demo here.
-
Creating Reusable Transitions
Now that transitions are applied via components, they are no longer considered an asset type, so the global Vue.transition() method and the transition option are both deprecated. You can just configure the transition inline with component props and events. But how do we create reusable transition effects now, especially those with custom JavaScript hooks? Well, the answer is creating your own transition components (they are particularly suitable as functional components):
Vue.component('fade', {
functional: true,
render (createElement, { children }) {
const data = {
props: {
name: 'fade'
},
on: {
beforeEnter () { /* ... */ }, // <-- Note hooks use camelCase in JavaScript (same as 1.x)
afterEnter () { /* ... */ }
}
}
return createElement('transition', data, children)
}
})
You can then use it like this:
<fade>
<div v-if="ok">toggled content</div>
</fade>
v-model changes
-
The lazy and number params are now modifiers:
<input v-model.lazy="text">
-
New modifier: .trim - trims the input, as the name suggests.
-
The debounce param has been deprecated. (See upgrade tip at bottom)
-
v-model no longer cares about initial inline value. It will always treat the Vue instance data as the source of truth. This means the following will render with a value of 1 instead of 2:
<input v-model="val" value="2">
Same goes for <textarea> with existing content. So instead of:
<textarea v-model="val">hello world</textarea>
Do:
data () {
return {
val: 'hello world'
}
}
<textarea v-model="val"></textarea>
The main idea is that the JS side should be considered the source of truth, not your templates.
-
v-model no longer works when used on a v-for iterated primitive value:
<input v-for="str in strings" v-model="str">
This doesn't work because it's the equivalent of this in JavaScript:
strings.map(function (str) {
return createElement('input', ...)
})
As you can see, setting str to another value in the iterator function will do nothing because it's just a local variable in the function scope. Instead, you should use an array of objects so that v-model can update the field on the object:
<input v-for="obj in objects" v-model="obj.str">
Props Behavior
.once and .sync are deprecated. Props are now always one-way down. To produce side effects in the parent scope, a component needs to explicitly emit an event instead of relying on implicit binding.
- Mutating a prop locally is now considered an anti-pattern, e.g. declaring a prop
a and then set this.a = someOtherValue in the component. Due to the new rendering mechanism, whenever the parent component re-renders, the child component's local changes will be overwritten. In general, in 2.0 you should treat props as immutable. Most use cases of mutating a prop can be replaced by either a data property or a computed property.
keep-alive
keep-alive is no longer a special attribute: it is now a wrapper component, similar to <transition>:
<keep-alive>
<component :is="view"></component>
</keep-alive>
This makes it possible to use keep-alive on multiple conditional children (note the children should eventually evaluate to a single child - any child other than the first one will be ignored):
<keep-alive>
<comp-a v-if="a > 1"></comp-a>
<comp-b v-else></comp-b>
</keep-alive>
When used together with <transition>, make sure to nest it inside:
<transition>
<keep-alive>
<component :is="view"></component>
</keep-alive>
</transition>
Slots
- It is no longer supported to have duplicate
<slot>s with the same name in the same template. When a slot is rendered it is "used up" and cannot be rendered elsewhere in the same render tree.
- Content inserted via named
<slot> no longer preserves the slot attribute. Use a wrapper element to style them, or, for advanced use cases, modify the inserted content programmatically using render functions.
Refs
-
v-ref is now no longer a directive: it is now a special attribute similar to key and transition:
<!-- before -->
<comp v-ref:foo></comp>
<!-- after -->
<comp ref="foo"></comp>
Dynamic ref bindings are now also supported:
<comp :ref="dynamicRef"></comp>
-
vm.$els and vm.$refs are merged. When used on a normal element the ref will be the DOM element, and when used on a component the ref will be the component instance.
-
vm.$refs are no longer reactive, because they are registered/updated during the render process itself. Making them reactive would require duplicate renders for every change.
On the other hand, $refs are designed primarily for programmatic access in JavaScript - it is not recommended to rely on $refs in templates because it entails referring to state that does not belong to the instance itself.
Misc
-
track-by has been replaced with key. It now follows the same rule for binding an attribute: without v-bind: or : prefix, it is treated as a literal string. In most cases you'd want to use a dynamic binding, which expects a full expression instead of a string key. For example:
<!-- 1.x -->
<div v-for="item in items" track-by="id">
<!-- 2.0 -->
<div v-for="item in items" :key="item.id">
-
Interpolation inside attributes are deprecated:
<!-- 1.x -->
<div id="{{ id }}">
<!-- 2.0 -->
<div :id="id">
-
Attribute binding behavior change: only null, undefined and false are considered falsy when binding attributes. This means 0 and empty strings will render as-is. For enumerated attributes. This means :draggable="''" will render as draggable="true".
Also, for enumerated attributes, in addition to the falsy values above, the string value of "false" will also render as attr="false".
-
When used on a custom component, v-on now only listens to custom events $emitted by that component. (no longer listens to DOM events)
-
v-else no longer works with v-show - just use negation expression.
-
One time bindings ({{* foo }}) deprecated - use v-once instead.
-
Array.prototype.$set/$remove deprecated (use Vue.set or Array.prototype.splice instead)
-
:style no longer supports inline !important
-
root instance can no longer use template props (use propsData instead)
-
The el option can no longer be used in Vue.extend. It can now only be used as an instance creation option.
-
Vue.set and Vue.delete cannot work on Vue instances. It is now mandatory to properly declare all top-level reactive properties in the data option.
-
It is now also prohibited to replace a component instance's root $data. This prevents some edge cases in the reactivity system and makes the component state more predictable (especially with type-checking systems).
-
User watchers created via vm.$watch are now fired before the associated component re-renders. This gives the user a chance to further update other state before the component re-render, thus avoiding unnecessary updates. For example, you can watch a component prop and update the component's own data when the prop changes.
To do something with the DOM after component updates, just use the updated lifecycle hook.
Upgrade Tips
How to Deal with Deprecation of $dispatch and $broadcast?
The reason that we are deprecating $dispatch and $broadcast is that event flows that depend on the components tree structure can be hard to reason about when the components tree becomes large (simply put: it doesn't scale well in large apps and we don't want to set you up for pain later). $dispatch and $broadcast also do not solve the communication between sibling components. Instead, you can use a pattern similar to the EventEmitter in Node.js: a centralized event hub that allows components to communicate, no matter where they are in the components tree. Because Vue instances implement the event emitter interface, you can actually use an empty Vue instance for that purpose:
// in component A's method
bus.$emit('id-selected', 1)
// in component B's created hook
bus.$on('id-selected', this.someMethod)
And don't forget to use $off to unbind the event.
// in component B's destroyed hook
bus.$off('id-selected', this.someMethod)
This pattern can serve as a replacement for $dispatch and $broadcast in simple scenarios. But for more complex cases, it is recommended to introduce a dedicated state management layer using Vuex.
How to Deal with the Deprecation of Array Filters?
For list filtering with v-for - one of the more common usage of filters - it is now recommended to use computed properties that return a processed copy of the original Array (see updated data grid example). The benefits is that you are no longer limited by the arbitrary filter syntax/API - it's just plain JavaScript now, and you naturally have access to the filtered result because it is a computed property.
Also see this discussion thread.
How to Deal with the Deprecation of debounce for v-model?
Debouncing is used to limit how often we execute Ajax requests and other expensive operations. Vue's debounce attribute parameter for v-model makes this easy, but it also debounces state updates rather than the expensive operations themselves, which comes with limitations.
These limitations become apparent when designing a search indicator. Take a look at that example. Using the debounce attribute, there'd be no way to detect a dirty input before the search begins, because we'd lose access to the input's real-time state. By decoupling the debounce function from Vue, we're able to debounce only the operation we want to limit.
There will be other times when debouncing isn't quite the right wrapper function. In the very common example of hitting an API for search suggestions, waiting to offer suggestions until after the user has stopped typing isn't an ideal experience. What you probably want instead is a throttling function. Now since you're already using a utility library like lodash for debounce, refactoring to use throttle instead takes only a few seconds!
General Notes
High Level Changes
<script type="text/x-template">, inline JavaScript strings, or compiled via single-file components), you are no longer subject to any of the template parsing limitations in 1.x. However, if you are relying on mounting to an element with existing content as template (using theeloption), you will still be subject to those limitations.vueifyorvue-loaderwill perform the template pre-compilation.Global config
logging the error stackthrowing in place)v-on.Vue.config.debugdeprecated, no longer useful since warnings come with stack traces by default nowVue.config.asyncdeprecated, async is required for rendering performanceVue.config.delimitersreworked as a component-level optionVue.config.unsafeDelimitersdeprecated, use v-htmlGlobal API
staggerdeprecated, set and access data-index onelinsteadVue.elementDirectivedeprecated, just use componentsVue.partialdeprecated, use functional componentsOptions
data
coercedeprecated. If you want to convert a prop, setup a local computed value based on it.prop binding modesdeprecated (v-model can work on components)DOM
replacedeprecated, components now must have exactly one root element.Lifecycle Hooks
initbeforeCreatereadydeprecated, use mounted (there's no longer the guarantee to be in-document)activatedeprecated, moved into vue-routerbeforeCompiledeprecated, use createdcompileddeprecated, use mountedattacheddeprecated, use custom in-dom check in other hooksdetacheddeprecated, same as aboveAssets
partialsdeprecatedelementDirectivesdeprecatedMisc
eventsdeprecated, since no more event propagationInstance Properties
vm.$elsdeprecated, merged with $refsInstance Methods
data
vm.$getdeprecated, just retrieve values directlyvm.$setdeprecated, use Vue.setvm.$deletedeprecated, use Vue.deletevm.$evaldeprecated, no real usevm.$interpolatedeprecated, no real usevm.$logdeprecated, use devtoolsevents
vm.$dispatchdeprecated, use global event bus or Vuex. (see below)vm.$broadcastdeprecated, same as aboveDOM
vm.$appendTodeprecated, just use native DOM API on vm.$el.vm.$beforedeprecatedvm.$afterdeprecatedvm.$removedeprecatedLifecycle
Directives
{{{ }}}shorthand has been deprecated(value, index) in arr,(value, key, index) in objdeprecated$indexand$keyVue.config.keyCodesinstead ofVue.directive('on').keyCodes)debouncedeprecated, use v-on:input + 3rd party debounce functionv-refnow just a special attribute asrefv-eldeprecated (merged with ref)Special Components
<component><transition><transition-group><keep-alive><slot>partialdeprecatedSpecial Attributes
Server-side Rendering
Other Breaking Changes
v-foriteration syntax changeDeprecating
$indexand$keyBoth of these are being deprecated in favor of more explicit named indices and keys. This syntax is a bit magical and has limitations in nested loops. As a bonus, there will be two fewer points of syntax for newcomers to learn.
New array syntax
value in arr(value, index) in arr(switched order of arguments to be more consistent with JavaScript'sforEachandmap)New object syntax
value in obj(value, key) in obj(switched order of arguments, partly to be more consistent with many common object iterators, such as lodash's)(value, key, index) in obj(index will now be available in object iteration for visual purposes, such as table striping)Directive interface change
In general, in 2.0 directives have a greatly reduced scope of responsibility: they are now only used for applying low-level direct DOM manipulations. In most cases, you should prefer using Components as the main code-reuse abstraction.
Directives no longer have instances - this means there's no more
thisinside directive hooks andbind,updateandunbindnow receives everything as arguments.Note the
bindingobject is immutable, settingbinding.valuewill have no effect, and properties added to it will not be persisted. You can persist directive state onelif you absolutely need to:You can use destructuring if you only care about the value:
In addition, the
updatehook has a few changes:bind.binding.value === binding.oldValueto skip unnecessary updates, but there are also cases where you'd want to always apply updates, e.g. when the directive is bound to an Object that might have been mutated instead of replaced.elementDirective, directive params and directive options such asacceptStatement,deepetc. are all deprecated.Filter Usage and Syntax Change
In Vue 2.0, there are several changes to the filter system:
Filters can now only be used inside text interpolations (
{{}}tags). In the past we've found using filters with directives such asv-model,v-onetc. led to more complexity than convenience, and for list filtering onv-forit is more appropriate to move that logic into JavaScript as computed properties.Vue 2.0 will not ship with any built-in filters. It is recommended to use standalone libraries dedicated for solving problems in a specific domain, e.g. moment.js for formatting dates and accounting.js for formatting financial currencies. You are also welcome to create your own filter pack and share it with the community!
The filter syntax has changed to be more inline with JavaScript function invocation, instead of taking space-delimited arguments:
Transition System
Transition CSS class changes:
The always-on
v-transitionclass is no longer added and Vue now uses the same classes Angular and React CSSTransitionGroup does:v-enter: applied before element is inserted, remove after 1 tick. (starting state for enter)v-enter-active: applied before element is inserted, removed when transition/animation finishes. (active + ending state for enter)v-leave: applied right when the leave transition is triggered, remove after 1 tick (starting state for leave)v-leave-active: applied right when the leave transition is triggered, removed when the transition/animation finishes. (active + ending state for leave)v-enter-activeandv-leave-activegives you the ability to specify different easing curves for enter/leave transitions. In most cases, upgrading means simply replacing your currentv-leavewithv-leave-active. (For CSS animations, usev-enter-active+v-leave-active)Transition API Change
The
<transition>componentAll single-element transition effects are now applied by wrapping the target element/component with the
<transition>built-in component. This is an abstract component, which means it does not render an extra DOM element, nor does it show up in the inspected component hierarchy. It simply applies the transition behavior to the wrapped content inside.The simplest usage example:
The component defines a number of props and events that maps directly to the old transition definition options:
Props
name: String
Used to automatically generate transition CSS class names. e.g.
name: 'fade'will auto expand to.fade-enter,.fade-enter-active, etc. Defaults to"v".appear: Boolean
Whether to apply transition on initial render. Defaults to
false.css: Boolean
Whether to apply CSS transition classes. Defaults to
true. If set tofalse, will only trigger JavaScript hooks registered via component events.type: String
Specify the type of transition events to wait for to determine transition end timing. Available values are
"transition"and"animation". By default, it will automatically detect the type that has a longer duration.mode: String
Controls the timing sequence of leaving/entering transitions. Available modes are
"out-in"and"in-out"; defaults to simultaneous.enterClass, leaveClass, enterActiveClass, leaveActiveClass, appearClass, appearActiveClass: String
Individually configure transition CSS classes.
Example applying transition to dynamic components:
Events
Corresponds to the JavaScript hooks available in 1.x API.
Example:
When the entering transition completes, the component's
transitionCompletemethod will be called with the transitioned DOM element as the argument.Some notes:
leave-cancelledis no longer available for insertion/removals. Once a leave transition starts, it cannot be cancelled. It is, however, still available forv-showtransitions.enterandleavehooks, the presence ofcbas the second argument indicates the user wants explicit control of the ending timing of the transition.The
<transition-group>componentAll multi-element transition effects are now applied by wrapping the elements with the
<transition-group>built-in component. It exposes the same props and events as<transition>does. The difference being that:<transition>,<transition-group>renders a real DOM element. By default it renders a<span>, and you can configure what element is should render via thetagprop. You can also use it with theisattribute, e.g.<ul is="transition-group">.<transition-group>does not support themodeprop.<transition-group>must be uniquely keyed.Example:
Moving Transitions
<transition-group>supports moving transitions via CSS transform. When a child's position on screen has changed after an updated, it will get applied a moving CSS class (auto generated from thenameprop or configured with themoveClassprop). If the CSStransformproperty is "transition-able" when the moving class is applied, the element will be smoothly animated to its destination using the FLIP technique.See a live demo here.
Creating Reusable Transitions
Now that transitions are applied via components, they are no longer considered an asset type, so the global
Vue.transition()method and thetransitionoption are both deprecated. You can just configure the transition inline with component props and events. But how do we create reusable transition effects now, especially those with custom JavaScript hooks? Well, the answer is creating your own transition components (they are particularly suitable as functional components):You can then use it like this:
v-model changes
The
lazyandnumberparams are now modifiers:New modifier:
.trim- trims the input, as the name suggests.The
debounceparam has been deprecated. (See upgrade tip at bottom)v-modelno longer cares about initial inlinevalue. It will always treat the Vue instance data as the source of truth. This means the following will render with a value of 1 instead of 2:Same goes for
<textarea>with existing content. So instead of:Do:
The main idea is that the JS side should be considered the source of truth, not your templates.
v-modelno longer works when used on av-foriterated primitive value:This doesn't work because it's the equivalent of this in JavaScript:
As you can see, setting
strto another value in the iterator function will do nothing because it's just a local variable in the function scope. Instead, you should use an array of objects so thatv-modelcan update the field on the object:Props Behavior
.onceand.syncare deprecated. Props are now always one-way down. To produce side effects in the parent scope, a component needs to explicitly emit an event instead of relying on implicit binding.aand then setthis.a = someOtherValuein the component. Due to the new rendering mechanism, whenever the parent component re-renders, the child component's local changes will be overwritten. In general, in 2.0 you should treat props as immutable. Most use cases of mutating a prop can be replaced by either a data property or a computed property.keep-alive
keep-aliveis no longer a special attribute: it is now a wrapper component, similar to<transition>:This makes it possible to use
keep-aliveon multiple conditional children (note the children should eventually evaluate to a single child - any child other than the first one will be ignored):When used together with
<transition>, make sure to nest it inside:Slots
<slot>s with the same name in the same template. When a slot is rendered it is "used up" and cannot be rendered elsewhere in the same render tree.<slot>no longer preserves theslotattribute. Use a wrapper element to style them, or, for advanced use cases, modify the inserted content programmatically using render functions.Refs
v-refis now no longer a directive: it is now a special attribute similar tokeyandtransition:Dynamic ref bindings are now also supported:
vm.$elsandvm.$refsare merged. When used on a normal element the ref will be the DOM element, and when used on a component the ref will be the component instance.vm.$refsare no longer reactive, because they are registered/updated during the render process itself. Making them reactive would require duplicate renders for every change.On the other hand,
$refsare designed primarily for programmatic access in JavaScript - it is not recommended to rely on$refsin templates because it entails referring to state that does not belong to the instance itself.Misc
track-byhas been replaced withkey. It now follows the same rule for binding an attribute: withoutv-bind:or:prefix, it is treated as a literal string. In most cases you'd want to use a dynamic binding, which expects a full expression instead of a string key. For example:Interpolation inside attributes are deprecated:
Attribute binding behavior change: only
null,undefinedandfalseare considered falsy when binding attributes. This means0and empty strings will render as-is. For enumerated attributes. This means:draggable="''"will render asdraggable="true".Also, for enumerated attributes, in addition to the falsy values above, the string value of "false" will also render as attr="false".
When used on a custom component,
v-onnow only listens to custom events $emitted by that component. (no longer listens to DOM events)v-elseno longer works withv-show- just use negation expression.One time bindings (
{{* foo }}) deprecated - usev-onceinstead.Array.prototype.$set/$remove deprecated (use Vue.set or Array.prototype.splice instead)
:styleno longer supports inline!importantroot instance can no longer use template props (use
propsDatainstead)The
eloption can no longer be used inVue.extend. It can now only be used as an instance creation option.Vue.setandVue.deletecannot work on Vue instances. It is now mandatory to properly declare all top-level reactive properties in thedataoption.It is now also prohibited to replace a component instance's root
$data. This prevents some edge cases in the reactivity system and makes the component state more predictable (especially with type-checking systems).User watchers created via
vm.$watchare now fired before the associated component re-renders. This gives the user a chance to further update other state before the component re-render, thus avoiding unnecessary updates. For example, you can watch a component prop and update the component's own data when the prop changes.To do something with the DOM after component updates, just use the updated lifecycle hook.
Upgrade Tips
How to Deal with Deprecation of
$dispatchand$broadcast?The reason that we are deprecating
$dispatchand$broadcastis that event flows that depend on the components tree structure can be hard to reason about when the components tree becomes large (simply put: it doesn't scale well in large apps and we don't want to set you up for pain later).$dispatchand$broadcastalso do not solve the communication between sibling components. Instead, you can use a pattern similar to the EventEmitter in Node.js: a centralized event hub that allows components to communicate, no matter where they are in the components tree. Because Vue instances implement the event emitter interface, you can actually use an empty Vue instance for that purpose:And don't forget to use $off to unbind the event.
This pattern can serve as a replacement for
$dispatchand$broadcastin simple scenarios. But for more complex cases, it is recommended to introduce a dedicated state management layer using Vuex.How to Deal with the Deprecation of Array Filters?
For list filtering with
v-for- one of the more common usage of filters - it is now recommended to use computed properties that return a processed copy of the original Array (see updated data grid example). The benefits is that you are no longer limited by the arbitrary filter syntax/API - it's just plain JavaScript now, and you naturally have access to the filtered result because it is a computed property.Also see this discussion thread.
How to Deal with the Deprecation of
debounceforv-model?Debouncing is used to limit how often we execute Ajax requests and other expensive operations. Vue's
debounceattribute parameter forv-modelmakes this easy, but it also debounces state updates rather than the expensive operations themselves, which comes with limitations.These limitations become apparent when designing a search indicator. Take a look at that example. Using the
debounceattribute, there'd be no way to detect a dirty input before the search begins, because we'd lose access to the input's real-time state. By decoupling the debounce function from Vue, we're able to debounce only the operation we want to limit.There will be other times when debouncing isn't quite the right wrapper function. In the very common example of hitting an API for search suggestions, waiting to offer suggestions until after the user has stopped typing isn't an ideal experience. What you probably want instead is a throttling function. Now since you're already using a utility library like lodash for
debounce, refactoring to usethrottleinstead takes only a few seconds!