Skip to content
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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

3.3 Updates #2348

Merged
merged 14 commits into from
May 11, 2023
147 changes: 89 additions & 58 deletions src/api/application.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,64 +90,6 @@ Unmounts a mounted application instance, triggering the unmount lifecycle hooks
}
```

## app.provide() {#app-provide}

Provide a value that can be injected in all descendant components within the application.

- **Type**

```ts
interface App {
provide<T>(key: InjectionKey<T> | symbol | string, value: T): this
}
```

- **Details**

Expects the injection key as the first argument, and the provided value as the second. Returns the application instance itself.

- **Example**

```js
import { createApp } from 'vue'

const app = createApp(/* ... */)

app.provide('message', 'hello')
```

Inside a component in the application:

<div class="composition-api">

```js
import { inject } from 'vue'

export default {
setup() {
console.log(inject('message')) // 'hello'
}
}
```

</div>
<div class="options-api">

```js
export default {
inject: ['message'],
created() {
console.log(this.message) // 'hello'
}
}
```

</div>

- **See also:**
- [Provide / Inject](/guide/components/provide-inject)
- [App-level Provide](/guide/components/provide-inject#app-level-provide)

## app.component() {#app-component}

Registers a global component if passing both a name string and a component definition, or retrieves an already registered one if only the name is passed.
Expand Down Expand Up @@ -270,6 +212,95 @@ For logic reuse, prefer [Composables](/guide/reusability/composables) instead.
}
```

## app.provide() {#app-provide}

Provide a value that can be injected in all descendant components within the application.

- **Type**

```ts
interface App {
provide<T>(key: InjectionKey<T> | symbol | string, value: T): this
}
```

- **Details**

Expects the injection key as the first argument, and the provided value as the second. Returns the application instance itself.

- **Example**

```js
import { createApp } from 'vue'

const app = createApp(/* ... */)

app.provide('message', 'hello')
```

Inside a component in the application:

<div class="composition-api">

```js
import { inject } from 'vue'

export default {
setup() {
console.log(inject('message')) // 'hello'
}
}
```

</div>
<div class="options-api">

```js
export default {
inject: ['message'],
created() {
console.log(this.message) // 'hello'
}
}
```

</div>

- **See also:**
- [Provide / Inject](/guide/components/provide-inject)
- [App-level Provide](/guide/components/provide-inject#app-level-provide)
- [app.runWithContext()](#app-runwithcontext)

## app.runWithContext()<sup class="vt-badge" data-text="3.3+" /> {#app-runwithcontext}

Execute a callback with the current app as injection context.

- **Type**

```ts
interface App {
runWithContext<T>(fn: () => T): T
}
```

- **Details**

Expects a callback function and runs the callback immediately. During the synchronous call of the callback, `inject()` calls are able to look up injections from the values provided by the current app, even when there is no current active component instance. The return value of the callback will also be returned.

- **Example**

```js
import { inject } from 'vue'

app.provide('id', 1)

const injected = app.runWithContext(() => {
return inject('id')
})

console.log(injected) // 1
```

## app.version {#app-version}

Provides the version of Vue that the application was created with. This is useful inside [plugins](/guide/reusability/plugins), where you might need conditional logic based on different Vue versions.
Expand Down
59 changes: 58 additions & 1 deletion src/api/general.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,16 @@ A type helper for defining a Vue component with type inference.
- **Type**

```ts
// options syntax
function defineComponent(
component: ComponentOptions | ComponentOptions['setup']
component: ComponentOptions
): ComponentConstructor

// function syntax (requires 3.3+)
function defineComponent(
setup: ComponentOptions['setup'],
extraOptions?: ComponentOptions
): () => any
```

> Type is simplified for readability.
Expand All @@ -122,6 +129,56 @@ A type helper for defining a Vue component with type inference.
type FooInstance = InstanceType<typeof Foo>
```

### Function Signature <sup class="vt-badge" data-text="3.3+" /> {#function-signature}

`defineComponent()` also has an alternative signature that is meant to be used with Composition API and [render functions or JSX](/guide/extras/render-function.html).

Instead of passing in an options object, a function is expected instead. This function works the same as the Composition API [`setup()`](/api/composition-api-setup.html#composition-api-setup) function: it receives the props and the setup context. The return value should be a render function - both `h()` and JSX are supported:

```js
import { ref, h } from 'vue'

const Comp = defineComponent(
(props) => {
// use Composition API here like in <script setup>
const count = ref(0)

return () => {
// render function or JSX
return h('div', count.value)
}
},
// extra options, e.g. declare props and emits
{
props: {
/* ... */
}
}
)
```

The main use case for this signature is with TypeScript (and in particular with TSX), as it supports generics:

```tsx
const Comp = defineComponent(
<T extends string | number>(props: { msg: T; list: T[] }) => {
// use Composition API here like in <script setup>
const count = ref(0)

return () => {
// render function or JSX
return <div>{count.value}</div>
}
},
// manual runtime props declaration is currently still needed.
{
props: ['msg', 'list']
}
)
```

In the future, we plan to provide a Babel plugin that automatically infers and injects the runtime props (like for `defineProps` in SFCs) so that the runtime props declaration can be omitted.

### Note on webpack Treeshaking {#note-on-webpack-treeshaking}

Because `defineComponent()` is a function call, it could look like that it would produce side-effects to some build tools, e.g. webpack. This will prevent the component from being tree-shaken even when the component is never used.
Expand Down
27 changes: 27 additions & 0 deletions src/api/options-rendering.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,30 @@ Configure runtime compiler options for the component's template.
This config option is only respected when using the full build (i.e. the standalone `vue.js` that can compile templates in the browser). It supports the same options as the app-level [app.config.compilerOptions](/api/application#app-config-compileroptions), and has higher priority for the current component.

- **See also:** [app.config.compilerOptions](/api/application#app-config-compileroptions)

## slots<sup class="vt-badge ts"/> {#slots}

An option to assist with type inference when using slots programmatically in render functions. Only supported in 3.3+.

- **Details**

This option's runtime value is not used. The actual types should be declared via type casting using the `SlotsType` type helper:

```ts
import { SlotsType } from 'vue'

defineComponent({
slots: Object as SlotsType<{
default: { foo: string; bar: number }
item: { data: number }
}>,
setup(props, { slots }) {
expectType<
undefined | ((scope: { foo: string; bar: number }) => any)
>(slots.default)
expectType<undefined | ((scope: { data: number }) => any)>(
slots.item
)
}
})
```
73 changes: 71 additions & 2 deletions src/api/reactivity-utilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,23 @@ Returns the inner value if the argument is a ref, otherwise return the argument

## toRef() {#toref}

Can be used to create a ref for a property on a source reactive object. The created ref is synced with its source property: mutating the source property will update the ref, and vice-versa.
Can be used to normalize values / refs / getters into refs (3.3+).

Can also be used to create a ref for a property on a source reactive object. The created ref is synced with its source property: mutating the source property will update the ref, and vice-versa.

- **Type**

```ts
// normalization signature (3.3+)
function toRef<T>(
value: T
): T extends () => infer R
? Readonly<Ref<R>>
: T extends Ref
? T
: Ref<UnwrapRef<T>>

// object property signature
function toRef<T extends object, K extends keyof T>(
object: T,
key: K,
Expand All @@ -57,12 +69,29 @@ Can be used to create a ref for a property on a source reactive object. The crea

- **Example**

Normalization signature (3.3+):

```js
// returns existing refs as-is
toRef(existingRef)

// creates a readonly ref that calls the getter on .value access
toRef(() => props.foo)

// creates normal refs from non-function values
// equivalent to ref(1)
toRef(1)
```

Object property signature:

```js
const state = reactive({
foo: 1,
bar: 2
})

// a two-way ref that syncs with the original property
const fooRef = toRef(state, 'foo')

// mutating the ref updates the original
Expand Down Expand Up @@ -93,12 +122,52 @@ Can be used to create a ref for a property on a source reactive object. The crea
// convert `props.foo` into a ref, then pass into
// a composable
useSomeFeature(toRef(props, 'foo'))

// getter syntax - recommended in 3.3+
useSomeFeature(toRef(() => props.foo))
</script>
```

When `toRef` is used with component props, the usual restrictions around mutating the props still apply. Attempting to assign a new value to the ref is equivalent to trying to modify the prop directly and is not allowed. In that scenario you may want to consider using [`computed`](./reactivity-core#computed) with `get` and `set` instead. See the guide to [using `v-model` with components](/guide/components/v-model) for more information.

`toRef()` will return a usable ref even if the source property doesn't currently exist. This makes it possible to work with optional properties, which wouldn't be picked up by [`toRefs`](#torefs).
When using the object property signature, `toRef()` will return a usable ref even if the source property doesn't currently exist. This makes it possible to work with optional properties, which wouldn't be picked up by [`toRefs`](#torefs).

## toValue() <sup class="vt-badge" data-text="3.3+" /> {#tovalue}

Normalizes values / refs / getters to values. This is similar to [unref()](#unref), except that it also normalizes getters. If the argument is a getter, it will be invoked and its return value will be returned.

This can be used in [Composables](/guide/reusability/composables.html) to normalize an argument that can be either a value, a ref, or a getter.

- **Type**

```ts
function toValue<T>(source: T | Ref<T> | (() => T)): T
```

- **Example**

```js
toValue(1) // --> 1
toValue(ref(1)) // --> 1
toValue(() => 1) // --> 1
```

Normalizing arguments in composables:

```ts
import type { MaybeRefOrGetter } from 'vue'

function useFeature(id: MaybeRefOrGetter<number>) {
watch(() => toValue(id), id => {
// react to id changes
})
}

// this composable supports any of the following:
useFeature(1)
useFeature(ref(1))
useFeature(() => 1)
```

## toRefs() {#torefs}

Expand Down