Skip to content

Commit 9a89e94

Browse files
docs: add the expose option and expose function (#1251)
1 parent a2bb521 commit 9a89e94

File tree

5 files changed

+123
-9
lines changed

5 files changed

+123
-9
lines changed

src/api/composition-api.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ A component option that is executed **before** the component is created, once th
4141
attrs: Data
4242
slots: Slots
4343
emit: (event: string, ...args: unknown[]) => void
44+
expose: (exposed?: Record<string, any>) => void
4445
}
4546

4647
function setup(props: Data, context: SetupContext): Data
@@ -89,12 +90,37 @@ A component option that is executed **before** the component is created, once th
8990
setup() {
9091
const readersNumber = ref(0)
9192
const book = reactive({ title: 'Vue 3 Guide' })
92-
// Please note that we need to explicitly expose ref value here
93+
// Please note that we need to explicitly use ref value here
9394
return () => h('div', [readersNumber.value, book.title])
9495
}
9596
}
9697
```
9798

99+
If you return a render function then you can't return any other properties. If you need to expose properties so that they can be accessed externally, e.g. via a `ref` in the parent, you can use `expose`:
100+
101+
```js
102+
// MyBook.vue
103+
104+
import { h } from 'vue'
105+
106+
export default {
107+
setup(props, { expose }) {
108+
const reset = () => {
109+
// Some reset logic
110+
}
111+
112+
// If you need to expose multiple properties they must all
113+
// be included in the object passed to expose. expose can
114+
// only be called once.
115+
expose({
116+
reset
117+
})
118+
119+
return () => h('div')
120+
}
121+
}
122+
```
123+
98124
- **See also**: [Composition API `setup`](../guide/composition-api-setup.html)
99125

100126
## Lifecycle Hooks

src/api/options-composition.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,18 +294,21 @@ The `setup` function is a new component option. It serves as the entry point for
294294

295295
The `props` object is immutable for userland code during development (will emit warning if user code attempts to mutate it).
296296

297-
The second argument provides a context object which exposes a selective list of properties that were previously exposed on `this`:
297+
The second argument provides a context object which exposes various objects and functions that might be useful in `setup`:
298298

299299
```js
300300
const MyComponent = {
301301
setup(props, context) {
302302
context.attrs
303303
context.slots
304304
context.emit
305+
context.expose
305306
}
306307
}
307308
```
308309

310+
`attrs`, `slots`, and `emit` are equivalent to the instance properties [`$attrs`](/api/instance-properties.html#attrs), [`$slots`](/api/instance-properties.html#slots), and [`$emit`](/api/instance-methods.html#emit) respectively.
311+
309312
`attrs` and `slots` are proxies to the corresponding values on the internal component instance. This ensures they always expose the latest values even after updates so that we can destructure them without worrying about accessing a stale reference:
310313

311314
```js
@@ -319,6 +322,26 @@ The `setup` function is a new component option. It serves as the entry point for
319322
}
320323
```
321324

325+
`expose`, added in Vue 3.2, is a function that allows specific properties to be exposed via the public component instance. By default, the public instance retrieved using refs, `$parent`, or `$root` is equivalent to the internal instance used by the template. Calling `expose` will create a separate public instance with the properties specified:
326+
327+
```js
328+
const MyComponent = {
329+
setup(props, { expose }) {
330+
const count = ref(0)
331+
const reset = () => count.value = 0
332+
const increment = () => count.value++
333+
334+
// Only reset will be available externally, e.g. via $refs
335+
expose({
336+
reset
337+
})
338+
339+
// Internally, the template has access to count and increment
340+
return { count, increment }
341+
}
342+
}
343+
```
344+
322345
There are a number of reasons for placing `props` as a separate first argument instead of including it in the context:
323346

324347
- It's much more common for a component to use `props` than the other properties, and very often a component uses only `props`.

src/api/options-data.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,3 +301,39 @@
301301
:::
302302

303303
* **See also:** [Attribute Inheritance](../guide/component-attrs.html#attribute-inheritance)
304+
305+
## expose <Badge text="3.2+" />
306+
307+
- **Type:** `Array<string>`
308+
309+
- **Details:**
310+
311+
A list of properties to expose on the public component instance.
312+
313+
By default, the public instance accessed via [`$refs`](/api/instance-properties.html#refs), [`$parent`](/api/instance-properties.html#parent), or [`$root`](/api/instance-properties.html#root) is the same as the internal component instance that's used by the template. The `expose` option restricts the properties that can be accessed via the public instance.
314+
315+
Properties defined by Vue itself, such as `$el` and `$parent`, will always be available on the public instance and don't need to be listed.
316+
317+
- **Usage:**
318+
319+
```js
320+
export default {
321+
// increment will be exposed but count
322+
// will only be accessible internally
323+
expose: ['increment'],
324+
325+
data() {
326+
return {
327+
count: 0
328+
}
329+
},
330+
331+
methods: {
332+
increment() {
333+
this.count++
334+
}
335+
}
336+
}
337+
```
338+
339+
- **See also:** [defineExpose](/api/sfc-script-setup.html#defineexpose)

src/guide/composition-api-setup.md

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,21 +64,24 @@ setup(props) {
6464

6565
### Context
6666

67-
The second argument passed to the `setup` function is the `context`. The `context` is a normal JavaScript object that exposes three component properties:
67+
The second argument passed to the `setup` function is the `context`. The `context` is a normal JavaScript object that exposes other values that may be useful inside `setup`:
6868

6969
```js
7070
// MyBook.vue
7171

7272
export default {
7373
setup(props, context) {
74-
// Attributes (Non-reactive object)
74+
// Attributes (Non-reactive object, equivalent to $attrs)
7575
console.log(context.attrs)
7676

77-
// Slots (Non-reactive object)
77+
// Slots (Non-reactive object, equivalent to $slots)
7878
console.log(context.slots)
7979

80-
// Emit Events (Method)
80+
// Emit events (Function, equivalent to $emit)
8181
console.log(context.emit)
82+
83+
// Expose public properties (Function)
84+
console.log(context.expose)
8285
}
8386
}
8487
```
@@ -88,13 +91,15 @@ The `context` object is a normal JavaScript object, i.e., it is not reactive, th
8891
```js
8992
// MyBook.vue
9093
export default {
91-
setup(props, { attrs, slots, emit }) {
94+
setup(props, { attrs, slots, emit, expose }) {
9295
...
9396
}
9497
}
9598
```
9699

97-
`attrs` and `slots` are stateful objects that are always updated when the component itself is updated. This means you should avoid destructuring them and always reference properties as `attrs.x` or `slots.x`. Also note that unlike `props`, `attrs` and `slots` are **not** reactive. If you intend to apply side effects based on `attrs` or `slots` changes, you should do so inside an `onUpdated` lifecycle hook.
100+
`attrs` and `slots` are stateful objects that are always updated when the component itself is updated. This means you should avoid destructuring them and always reference properties as `attrs.x` or `slots.x`. Also note that, unlike `props`, the properties of `attrs` and `slots` are **not** reactive. If you intend to apply side effects based on changes to `attrs` or `slots`, you should do so inside an `onBeforeUpdate` lifecycle hook.
101+
102+
We'll explain the role of `expose` shortly.
98103

99104
## Accessing Component Properties
100105

@@ -157,12 +162,35 @@ export default {
157162
setup() {
158163
const readersNumber = ref(0)
159164
const book = reactive({ title: 'Vue 3 Guide' })
160-
// Please note that we need to explicitly expose ref value here
165+
// Please note that we need to explicitly use ref value here
161166
return () => h('div', [readersNumber.value, book.title])
162167
}
163168
}
164169
```
165170

171+
Returning a render function prevents us from returning anything else. Internally that shouldn't be a problem, but it can be problematic if we want to expose methods of this component to the parent component via template refs.
172+
173+
We can solve this problem by calling `expose`, passing it an object that defines the properties that should be available on the external component instance:
174+
175+
```js
176+
import { h, ref } from 'vue'
177+
178+
export default {
179+
setup(props, { expose }) {
180+
const count = ref(0)
181+
const increment = () => ++count.value
182+
183+
expose({
184+
increment
185+
})
186+
187+
return () => h('div', count.value)
188+
}
189+
}
190+
```
191+
192+
The `increment` method would then be available in the parent component via a template ref.
193+
166194
## Usage of `this`
167195

168196
**Inside `setup()`, `this` won't be a reference to the current active instance** Since `setup()` is called before other component options are resolved, `this` inside `setup()` will behave quite differently from `this` in other options. This might cause confusions when using `setup()` along other Options API.

src/style-guide/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1284,6 +1284,7 @@ This is the default order we recommend for component options. They're split into
12841284
- `inheritAttrs`
12851285
- `props`
12861286
- `emits`
1287+
- `expose`
12871288

12881289
6. **Composition API** (the entry point for using the Composition API)
12891290
- `setup`

0 commit comments

Comments
 (0)