Skip to content

Commit 9e3d61a

Browse files
docs: use destructuring to access createApp, etc. in render-function.md (#803)
1 parent 4f4a5e6 commit 9e3d61a

File tree

1 file changed

+57
-43
lines changed

1 file changed

+57
-43
lines changed

src/guide/render-function.md

Lines changed: 57 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ Anchored headings are used very frequently, we should create a component:
2121
The component must generate a heading based on the `level` prop, and we quickly arrive at this:
2222

2323
```js
24-
const app = Vue.createApp({})
24+
const { createApp } = Vue
25+
26+
const app = createApp({})
2527

2628
app.component('anchored-heading', {
2729
template: `
@@ -58,11 +60,13 @@ This template doesn't feel great. It's not only verbose, but we're duplicating `
5860
While templates work great for most components, it's clear that this isn't one of them. So let's try rewriting it with a `render()` function:
5961

6062
```js
61-
const app = Vue.createApp({})
63+
const { createApp, h } = Vue
64+
65+
const app = createApp({})
6266

6367
app.component('anchored-heading', {
6468
render() {
65-
return Vue.h(
69+
return h(
6670
'h' + this.level, // tag name
6771
{}, // props/attributes
6872
this.$slots.default() // array of children
@@ -109,7 +113,7 @@ Or in a render function:
109113

110114
```js
111115
render() {
112-
return Vue.h('h1', {}, this.blogTitle)
116+
return h('h1', {}, this.blogTitle)
113117
}
114118
```
115119

@@ -120,7 +124,7 @@ And in both cases, Vue automatically keeps the page updated, even when `blogTitl
120124
Vue keeps the page updated by building a **virtual DOM** to keep track of the changes it needs to make to the real DOM. Taking a closer look at this line:
121125

122126
```js
123-
return Vue.h('h1', {}, this.blogTitle)
127+
return h('h1', {}, this.blogTitle)
124128
```
125129

126130
What is the `h()` function returning? It's not _exactly_ a real DOM element. It returns a plain object which contains information describing to Vue what kind of node it should render on the page, including descriptions of any child nodes. We call this node description a "virtual node", usually abbreviated to **VNode**. "Virtual DOM" is what we call the entire tree of VNodes, built by a tree of Vue components.
@@ -169,7 +173,9 @@ If there are no props then the children can usually be passed as the second argu
169173
With this knowledge, we can now finish the component we started:
170174

171175
```js
172-
const app = Vue.createApp({})
176+
const { createApp, h } = Vue
177+
178+
const app = createApp({})
173179

174180
/** Recursively get text from children nodes */
175181
function getChildrenTextContent(children) {
@@ -192,8 +198,8 @@ app.component('anchored-heading', {
192198
.replace(/\W+/g, '-') // replace non-word characters with dash
193199
.replace(/(^-|-$)/g, '') // remove leading and trailing dashes
194200

195-
return Vue.h('h' + this.level, [
196-
Vue.h(
201+
return h('h' + this.level, [
202+
h(
197203
'a',
198204
{
199205
name: headingId,
@@ -220,8 +226,8 @@ All VNodes in the component tree must be unique. That means the following render
220226

221227
```js
222228
render() {
223-
const myParagraphVNode = Vue.h('p', 'hi')
224-
return Vue.h('div', [
229+
const myParagraphVNode = h('p', 'hi')
230+
return h('div', [
225231
// Yikes - duplicate VNodes!
226232
myParagraphVNode, myParagraphVNode
227233
])
@@ -232,9 +238,9 @@ If you really want to duplicate the same element/component many times, you can d
232238

233239
```js
234240
render() {
235-
return Vue.h('div',
241+
return h('div',
236242
Array.from({ length: 20 }).map(() => {
237-
return Vue.h('p', 'hi')
243+
return h('p', 'hi')
238244
})
239245
)
240246
}
@@ -246,16 +252,20 @@ To create a VNode for a component, the first argument passed to `h` should be th
246252

247253
```js
248254
render() {
249-
return Vue.h(ButtonCounter)
255+
return h(ButtonCounter)
250256
}
251257
```
252258

253259
If we need to resolve a component by name then we can call `resolveComponent`:
254260

255261
```js
262+
const { h, resolveComponent } = Vue
263+
264+
// ...
265+
256266
render() {
257-
const ButtonCounter = Vue.resolveComponent('ButtonCounter')
258-
return Vue.h(ButtonCounter)
267+
const ButtonCounter = resolveComponent('ButtonCounter')
268+
return h(ButtonCounter)
259269
}
260270
```
261271

@@ -269,15 +279,15 @@ components: {
269279
ButtonCounter
270280
},
271281
render() {
272-
return Vue.h(Vue.resolveComponent('ButtonCounter'))
282+
return h(resolveComponent('ButtonCounter'))
273283
}
274284
```
275285

276286
Rather than registering a component by name and then looking it up we can use it directly instead:
277287

278288
```js
279289
render() {
280-
return Vue.h(ButtonCounter)
290+
return h(ButtonCounter)
281291
}
282292
```
283293

@@ -300,11 +310,11 @@ This could be rewritten with JavaScript's `if`/`else` and `map()` in a render fu
300310
props: ['items'],
301311
render() {
302312
if (this.items.length) {
303-
return Vue.h('ul', this.items.map((item) => {
304-
return Vue.h('li', item.name)
313+
return h('ul', this.items.map((item) => {
314+
return h('li', item.name)
305315
}))
306316
} else {
307-
return Vue.h('p', 'No items found.')
317+
return h('p', 'No items found.')
308318
}
309319
}
310320
```
@@ -319,7 +329,7 @@ The `v-model` directive is expanded to `modelValue` and `onUpdate:modelValue` pr
319329
props: ['modelValue'],
320330
emits: ['update:modelValue'],
321331
render() {
322-
return Vue.h(SomeComponent, {
332+
return h(SomeComponent, {
323333
modelValue: this.modelValue,
324334
'onUpdate:modelValue': value => this.$emit('update:modelValue', value)
325335
})
@@ -332,7 +342,7 @@ We have to provide a proper prop name for the event handler, e.g., to handle `cl
332342

333343
```js
334344
render() {
335-
return Vue.h('div', {
345+
return h('div', {
336346
onClick: $event => console.log('clicked', $event.target)
337347
})
338348
}
@@ -346,7 +356,7 @@ For example:
346356

347357
```javascript
348358
render() {
349-
return Vue.h('input', {
359+
return h('input', {
350360
onClickCapture: this.doThisInCapturingMode,
351361
onKeyupOnce: this.doThisOnce,
352362
onMouseoverOnceCapture: this.doThisOnceInCapturingMode
@@ -368,7 +378,7 @@ Here's an example with all of these modifiers used together:
368378

369379
```js
370380
render() {
371-
return Vue.h('input', {
381+
return h('input', {
372382
onKeyUp: event => {
373383
// Abort if the element emitting the event is not
374384
// the element the event is bound to
@@ -394,15 +404,15 @@ We can access slot contents as arrays of VNodes from [`this.$slots`](../api/inst
394404
```js
395405
render() {
396406
// `<div><slot></slot></div>`
397-
return Vue.h('div', this.$slots.default())
407+
return h('div', this.$slots.default())
398408
}
399409
```
400410

401411
```js
402412
props: ['message'],
403413
render() {
404414
// `<div><slot :text="message"></slot></div>`
405-
return Vue.h('div', this.$slots.default({
415+
return h('div', this.$slots.default({
406416
text: this.message
407417
}))
408418
}
@@ -413,14 +423,14 @@ For component VNodes, we need to pass the children to `h` as an object rather th
413423
```js
414424
render() {
415425
// `<div><child v-slot="props"><span>{{ props.text }}</span></child></div>`
416-
return Vue.h('div', [
417-
Vue.h(
418-
Vue.resolveComponent('child'),
426+
return h('div', [
427+
h(
428+
resolveComponent('child'),
419429
null,
420430
// pass `slots` as the children object
421431
// in the form of { name: props => VNode | Array<VNode> }
422432
{
423-
default: (props) => Vue.h('span', props.text)
433+
default: (props) => h('span', props.text)
424434
}
425435
)
426436
])
@@ -433,10 +443,10 @@ The slots are passed as functions, allowing the child component to control the c
433443
// `<MyButton><MyIcon :name="icon" />{{ text }}</MyButton>`
434444
render() {
435445
// Calls to resolveComponent should be outside the slot function
436-
const Button = Vue.resolveComponent('MyButton')
437-
const Icon = Vue.resolveComponent('MyIcon')
446+
const Button = resolveComponent('MyButton')
447+
const Icon = resolveComponent('MyIcon')
438448

439-
return Vue.h(
449+
return h(
440450
Button,
441451
null,
442452
{
@@ -445,7 +455,7 @@ render() {
445455
// Reactive properties should be read inside the slot function
446456
// so that they become dependencies of the child's rendering
447457
return [
448-
Vue.h(Icon, { name: this.icon }),
458+
h(Icon, { name: this.icon }),
449459
this.text
450460
]
451461
}
@@ -458,15 +468,15 @@ If a component receives slots from its parent, they can be passed on directly to
458468

459469
```js
460470
render() {
461-
return Vue.h(Panel, null, this.$slots)
471+
return h(Panel, null, this.$slots)
462472
}
463473
```
464474

465475
They can also be passed individually or wrapped as appropriate:
466476

467477
```js
468478
render() {
469-
return Vue.h(
479+
return h(
470480
Panel,
471481
null,
472482
{
@@ -478,7 +488,7 @@ render() {
478488
default: (props) => {
479489
const children = this.$slots.default ? this.$slots.default(props) : []
480490

481-
return children.concat(Vue.h('div', 'Extra child'))
491+
return children.concat(h('div', 'Extra child'))
482492
}
483493
}
484494
)
@@ -490,10 +500,14 @@ render() {
490500
Behind the scenes, templates use `resolveDynamicComponent` to implement the `is` attribute. We can use the same function if we need all the flexibility provided by `is` in our `render` function:
491501

492502
```js
503+
const { h, resolveDynamicComponent } = Vue
504+
505+
// ...
506+
493507
// `<component :is="name"></component>`
494508
render() {
495-
const Component = Vue.resolveDynamicComponent(this.name)
496-
return Vue.h(Component)
509+
const Component = resolveDynamicComponent(this.name)
510+
return h(Component)
497511
}
498512
```
499513

@@ -508,7 +522,7 @@ If the VNode is always an HTML element then we can pass its name directly to `h`
508522
```js
509523
// `<component :is="bold ? 'strong' : 'em'"></component>`
510524
render() {
511-
return Vue.h(this.bold ? 'strong' : 'em')
525+
return h(this.bold ? 'strong' : 'em')
512526
}
513527
```
514528

@@ -521,13 +535,13 @@ Much like a `<template>` tag, a `<component>` tag is only required in templates
521535
If we're writing a lot of `render` functions, it might feel painful to write something like this:
522536

523537
```js
524-
Vue.h(
525-
Vue.resolveComponent('anchored-heading'),
538+
h(
539+
resolveComponent('anchored-heading'),
526540
{
527541
level: 1
528542
},
529543
{
530-
default: () => [Vue.h('span', 'Hello'), ' world!']
544+
default: () => [h('span', 'Hello'), ' world!']
531545
}
532546
)
533547
```

0 commit comments

Comments
 (0)