Render Function API breaking
Overview
This change will not affect <template>
users.
Here is a quick summary of what has changed:
h
is now globally imported instead of passed to render functions as an argument- render function arguments changed to be more consistent between stateful and functional components
- VNodes now have a flat props structure
For more information, read on!
Render Function Argument
2.x Syntax
In 2.x, the render
function would automatically receive the h
function (which is a conventional alias for createElement
) as an argument:
// Vue 2 Render Function Example
export default {
render(h) {
return h('div')
}
}
3.x Syntax
In 3.x, h
is now globally imported instead of being automatically passed as an argument.
// Vue 3 Render Function Example
import { h } from 'vue'
export default {
render() {
return h('div')
}
}
VNode Props Format
2.x Syntax
In 2.x, domProps
contained a nested list within the VNode props:
// 2.x
{
staticClass: 'button',
class: {'is-outlined': isOutlined },
staticStyle: { color: '#34495E' },
style: { backgroundColor: buttonColor },
attrs: { id: 'submit' },
domProps: { innerHTML: '' },
on: { click: submitForm },
key: 'submit-button'
}
3.x Syntax
In 3.x, the entire VNode props structure is flattened. Using the example from above, here is what it would look like now.
// 3.x Syntax
{
class: ['button', { 'is-outlined': isOutlined }],
style: [{ color: '#34495E' }, { backgroundColor: buttonColor }],
id: 'submit',
innerHTML: '',
onClick: submitForm,
key: 'submit-button'
}
Registered Component
2.x Syntax
In 2.x, when a component has been registered, the render function would work well when passing the component's name as a string to the first argument:
// 2.x
Vue.component('button-counter', {
data() {
return {
count: 0
}
}
template: `
<button @click="count++">
Clicked {{ count }} times.
</button>
`
})
export default {
render(h) {
return h('button-counter')
}
}
3.x Syntax
In 3.x, with VNodes being context-free, we can no longer use a string ID to implicitly lookup registered components. Instead, we need to use an imported resolveComponent
method:
// 3.x
import { h, resolveComponent } from 'vue'
export default {
setup() {
const ButtonCounter = resolveComponent('button-counter')
return () => h(ButtonCounter)
}
}
For more information, see The Render Function Api Change RFC.
Migration Strategy
Migration build flag: RENDER_FUNCTION
Library Authors
h
being globally imported means that any library that contains Vue components will include import { h } from 'vue'
somewhere. As a result, this creates a bit of overhead since it requires library authors to properly configure the externalization of Vue in their build setup:
- Vue should not be bundled into the library
- For module builds, the import should be left alone and be handled by the end user bundler
- For UMD / browser builds, it should try the global Vue.h first and fallback to require calls
Next Steps
See Render Function Guide for more detailed documentation!