diff --git a/src/api/basic-reactivity.md b/src/api/basic-reactivity.md index 8fed58a1..6efea0e8 100644 --- a/src/api/basic-reactivity.md +++ b/src/api/basic-reactivity.md @@ -18,6 +18,44 @@ The reactive conversion is "deep"—it affects all nested properties. In the [ES function reactive(target: T): UnwrapNestedRefs ``` +::: tip Note +`reactive` will unwrap all the deep [refs](./refs-api.html#ref), while maintaining the ref reactivity + +```ts +const count = ref(1) +const obj = reactive({ count }) + +// ref will be unwrapped +console.log(obj.count === count.value) // true + +// it will update `obj.count` +count.value++ +console.log(count.value) // 2 +console.log(obj.count) // 2 + +// it will also update `count` ref +obj.count++ +console.log(obj.count) // 3 +console.log(count.value) // 3 +``` + +::: + +::: warning Important +When assigning a [ref](./refs-api.html#ref) to a `reactive` property, that ref will be automatically unwrapped. + +```ts +const count = ref(1) +const obj = reactive({}) + +obj.count = count + +console.log(obj.count) // 1 +console.log(obj.count === count.value) // true +``` + +::: + ## `readonly` Takes an object (reactive or plain) or a [ref](./refs-api.html#ref) and returns a readonly proxy to the original. A readonly proxy is deep: any nested property accessed will be readonly as well. @@ -39,6 +77,19 @@ original.count++ copy.count++ // warning! ``` +As with [`reactive`](#reactive), if any property uses a `ref` it will be automatically unwrapped when it is accessed via the proxy: + +```js +const raw = { + count: ref(123) +} + +const copy = readonly(raw) + +console.log(raw.count.value) // 123 +console.log(copy.count) // 123 +``` + ## `isProxy` Checks if an object is a proxy created by [`reactive`](#reactive) or [`readonly`](#readonly). @@ -153,6 +204,8 @@ isReactive(state.nested) // false state.nested.bar++ // non-reactive ``` +Unlike [`reactive`](#reactive), any property that uses a [`ref`](/api/refs-api.html#ref) will **not** be automatically unwrapped by the proxy. + ## `shallowReadonly` Creates a proxy that makes its own properties readonly, but does not perform deep readonly conversion of nested objects (exposes raw values). @@ -171,3 +224,5 @@ state.foo++ isReadonly(state.nested) // false state.nested.bar++ // works ``` + +Unlike [`readonly`](#readonly), any property that uses a [`ref`](/api/refs-api.html#ref) will **not** be automatically unwrapped by the proxy. diff --git a/src/api/computed-watch-api.md b/src/api/computed-watch-api.md index 124a3d0a..f691c730 100644 --- a/src/api/computed-watch-api.md +++ b/src/api/computed-watch-api.md @@ -65,7 +65,7 @@ function watchEffect( ): StopHandle interface WatchEffectOptions { - flush?: 'pre' | 'post' | 'sync' + flush?: 'pre' | 'post' | 'sync' // default: 'pre' onTrack?: (event: DebuggerEvent) => void onTrigger?: (event: DebuggerEvent) => void } @@ -132,7 +132,7 @@ watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => { **Typing:** ```ts -// wacthing single source +// watching single source function watch( source: WatcherSource, callback: ( diff --git a/src/api/instance-methods.md b/src/api/instance-methods.md index e042a22a..f7ae1d64 100644 --- a/src/api/instance-methods.md +++ b/src/api/instance-methods.md @@ -9,17 +9,18 @@ - `{Object} options (optional)` - `{boolean} deep` - `{boolean} immediate` + - `{string} flush` - **Returns:** `{Function} unwatch` - **Usage:** - Watch a reactive property or a computed function on the component instance for changes. The callback gets called with the new value and the old value for the given property. We can only pass top-level `data`, `prop`, or `computed` property name as a string. For more complex expressions or nested properties, use a function instead. + Watch a reactive property or a computed function on the component instance for changes. The callback gets called with the new value and the old value for the given property. We can only pass top-level `data`, `props`, or `computed` property name as a string. For more complex expressions or nested properties, use a function instead. - **Example:** ```js - const app = Vue.createApp({ + const app = createApp({ data() { return { a: 1, @@ -58,10 +59,10 @@ }) ``` - When watched value is an Object or Array, any changes to its properties or elements won't trigger the watcher because they reference the same Object/Array: + When watched value is an object or array, any changes to its properties or elements won't trigger the watcher because they reference the same object/array: ```js - const app = Vue.createApp({ + const app = createApp({ data() { return { article: { @@ -80,8 +81,8 @@ }) }, methods: { - // These methods won't trigger a watcher because we changed only a property of Object/Array, - // not the Object/Array itself + // These methods won't trigger a watcher because we changed only a property of object/array, + // not the object/array itself changeArticleText() { this.article.text = 'Vue 3 is awesome' }, @@ -89,7 +90,7 @@ this.comments.push('New comment') }, - // These methods will trigger a watcher because we replaced Object/Array completely + // These methods will trigger a watcher because we replaced object/array completely changeWholeArticle() { this.article = { text: 'Vue 3 is awesome' } }, @@ -103,7 +104,7 @@ `$watch` returns an unwatch function that stops firing the callback: ```js - const app = Vue.createApp({ + const app = createApp({ data() { return { a: 1 @@ -120,7 +121,9 @@ - **Option: deep** - To also detect nested value changes inside Objects, you need to pass in `deep: true` in the options argument. Note that you don't need to do so to listen for Array mutations. + To also detect nested value changes inside Objects, you need to pass in `deep: true` in the options argument. This option also can be used to watch array mutations. + + > Note: when mutating (rather than replacing) an Object or an Array and watch with deep option, the old value will be the same as new value because they reference the same Object/Array. Vue doesn't keep a copy of the pre-mutate value. ```js vm.$watch('someObject', callback, { @@ -158,7 +161,9 @@ If you still want to call an unwatch function inside the callback, you should check its availability first: ```js - const unwatch = vm.$watch( + let unwatch = null + + unwatch = vm.$watch( 'value', function() { doSomething() @@ -170,6 +175,24 @@ ) ``` +- **Option: flush** + + The `flush` option allows for greater control over the timing of the callback. It can be set to `'pre'`, `'post'` or `'sync'`. + + The default value is `'pre'`, which specifies that the callback should be invoked before rendering. This allows the callback to update other values before the template runs. + + The value `'post'` can be used to defer the callback until after rendering. This should be used if the callback needs access to the updated DOM or child components via `$refs`. + + If `flush` is set to `'sync'`, the callback will be called synchronously, as soon as the value changes. + + For both `'pre'` and `'post'`, the callback is buffered using a queue. The callback will only be added to the queue once, even if the watched value changes multiple times. The interim values will be skipped and won't be passed to the callback. + + Buffering the callback not only improves performance but also helps to ensure data consistency. The watchers won't be triggered until the code performing the data updates has finished. + + `'sync'` watchers should be used sparingly, as they don't have these benefits. + + For more information about `flush` see [Effect Flush Timing](../guide/reactivity-computed-watchers.html#effect-flush-timing). + - **See also:** [Watchers](../guide/computed.html#watchers) ## $emit @@ -272,7 +295,7 @@ - **Example:** ```js - Vue.createApp({ + createApp({ // ... methods: { // ... diff --git a/src/api/instance-properties.md b/src/api/instance-properties.md index 3ab0f5fd..d623545c 100644 --- a/src/api/instance-properties.md +++ b/src/api/instance-properties.md @@ -28,6 +28,8 @@ The root DOM element that the component instance is managing. + For components using [fragments](../guide/migration/fragments), `$el` will be the placeholder DOM node that Vue uses to keep track of the component's position in the DOM. It is recommended to use [template refs](../guide/component-template-refs.html) for direct access to DOM elements instead of relying on `$el`. + ## $options - **Type:** `Object` @@ -39,7 +41,7 @@ The instantiation options used for the current component instance. This is useful when you want to include custom properties in the options: ```js - const app = Vue.createApp({ + const app = createApp({ customOption: 'foo', created() { console.log(this.$options.customOption) // => 'foo' @@ -100,14 +102,15 @@ ``` ```js - const app = Vue.createApp({}) + const { createApp, h } = Vue + const app = createApp({}) app.component('blog-post', { render() { - return Vue.h('div', [ - Vue.h('header', this.$slots.header()), - Vue.h('main', this.$slots.default()), - Vue.h('footer', this.$slots.footer()) + return h('div', [ + h('header', this.$slots.header()), + h('main', this.$slots.default()), + h('footer', this.$slots.footer()) ]) } }) @@ -144,3 +147,4 @@ Contains parent-scope attribute bindings and events that are not recognized (and - **See also:** - [Non-Prop Attributes](../guide/component-attrs.html) + - [Options / Misc - inheritAttrs](./options-misc.html#inheritattrs) diff --git a/src/api/options-api.md b/src/api/options-api.md index a5544492..405a99f9 100644 --- a/src/api/options-api.md +++ b/src/api/options-api.md @@ -1,10 +1,10 @@ -# オプション +# オプション API -オプションには、次のようなセクションがあります: +オプション API には、次のようなセクションがあります: - [Data](/api/options-data.html) - [DOM](/api/options-dom.html) - [Lifecycle Hooks](/api/options-lifecycle-hooks.html) - [Assets](/api/options-assets.html) - [Composition](/api/options-composition.html) -- [Misc](/api/options-misc.html) +- [Miscellaneous](/api/options-misc.html) diff --git a/src/api/options-assets.md b/src/api/options-assets.md index 2ac7d507..e19d4362 100644 --- a/src/api/options-assets.md +++ b/src/api/options-assets.md @@ -8,6 +8,23 @@ A hash of directives to be made available to the component instance. +- **Usage:** + + ```js + const app = createApp({}) + + app.component('focused-input', { + directives: { + focus: { + mounted(el) { + el.focus() + } + } + }, + template: `` + }) + ``` + - **See also:** [Custom Directives](../guide/custom-directive.html) ## components @@ -18,4 +35,19 @@ A hash of components to be made available to the component instance. +- **Usage:** + + ```js + const Foo = { + template: `
Foo
` + } + + const app = createApp({ + components: { + Foo + }, + template: `` + }) + ``` + - **See also:** [Components](../guide/component-basics.html) diff --git a/src/api/options-composition.md b/src/api/options-composition.md index 689b01f6..ac850701 100644 --- a/src/api/options-composition.md +++ b/src/api/options-composition.md @@ -19,7 +19,7 @@ } } - Vue.createApp({ + createApp({ created() { console.log(2) }, @@ -299,7 +299,7 @@ The `setup` function is a new component option. It serves as the entry point for } ``` - `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 accessing a stale reference: + `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: ```js const MyComponent = { diff --git a/src/api/options-lifecycle-hooks.md b/src/api/options-lifecycle-hooks.md index aa0b6612..dab2e2e3 100644 --- a/src/api/options-lifecycle-hooks.md +++ b/src/api/options-lifecycle-hooks.md @@ -42,9 +42,9 @@ All lifecycle hooks automatically have their `this` context bound to the instanc - **Details:** - Called after the instance has been mounted, where element, passed to `Vue.createApp({}).mount()` is replaced by the newly created `vm.$el`. If the root instance is mounted to an in-document element, `vm.$el` will also be in-document when `mounted` is called. + Called after the instance has been mounted, where element, passed to [`app.mount`](/api/application-api.html#mount) is replaced by the newly created `vm.$el`. If the root instance is mounted to an in-document element, `vm.$el` will also be in-document when `mounted` is called. - Note that `mounted` does **not** guarantee that all child components have also been mounted. If you want to wait until the entire view has been rendered, you can use [vm.\$nextTick](../api/instance-methods.html#nexttick) inside of `mounted`: + Note that `mounted` does **not** guarantee that all child components have also been mounted. If you want to wait until the entire view has been rendered, you can use [vm.$nextTick](../api/instance-methods.html#nexttick) inside of `mounted`: ```js mounted() { @@ -81,7 +81,7 @@ All lifecycle hooks automatically have their `this` context bound to the instanc The component's DOM will have been updated when this hook is called, so you can perform DOM-dependent operations here. However, in most cases you should avoid changing state inside the hook. To react to state changes, it's usually better to use a [computed property](./options-data.html#computed) or [watcher](./options-data.html#watch) instead. - Note that `updated` does **not** guarantee that all child components have also been re-rendered. If you want to wait until the entire view has been re-rendered, you can use [vm.\$nextTick](../api/instance-methods.html#nexttick) inside of `updated`: + Note that `updated` does **not** guarantee that all child components have also been re-rendered. If you want to wait until the entire view has been re-rendered, you can use [vm.$nextTick](../api/instance-methods.html#nexttick) inside of `updated`: ```js updated() { @@ -107,7 +107,7 @@ All lifecycle hooks automatically have their `this` context bound to the instanc **This hook is not called during server-side rendering.** - **See also:** - - [Dynamic Components - keep-alive](../guide/component-basics.html#keep-alive) + - [Dynamic Components - keep-alive](../guide/component-dynamic-async.html#dynamic-components-with-keep-alive) ## deactivated @@ -120,7 +120,7 @@ All lifecycle hooks automatically have their `this` context bound to the instanc **This hook is not called during server-side rendering.** - **See also:** - - [Dynamic Components - keep-alive](../guide/component-basics.html#keep-alive) + - [Dynamic Components - keep-alive](../guide/component-dynamic-async.html#dynamic-components-with-keep-alive) ## beforeUnmount @@ -186,7 +186,7 @@ All lifecycle hooks automatically have their `this` context bound to the instanc ``` ```js - const app = Vue.createApp({ + const app = createApp({ data() { return { cart: 0 @@ -220,7 +220,7 @@ All lifecycle hooks automatically have their `this` context bound to the instanc - **Details:** - Called when virtual DOM re-render is triggered.Similarly to [`renderTracked`](#rendertracked), receives a `debugger event` as an argument. This event tells you what operation triggered the re-rendering and the target object and key of that operation. + Called when virtual DOM re-render is triggered. Similarly to [`renderTracked`](#rendertracked), receives a `debugger event` as an argument. This event tells you what operation triggered the re-rendering and the target object and key of that operation. - **Usage:** @@ -232,7 +232,7 @@ All lifecycle hooks automatically have their `this` context bound to the instanc ``` ```js - const app = Vue.createApp({ + const app = createApp({ data() { return { cart: 0 diff --git a/src/api/refs-api.md b/src/api/refs-api.md index 46d26f49..6fcdbb67 100644 --- a/src/api/refs-api.md +++ b/src/api/refs-api.md @@ -38,7 +38,7 @@ foo.value = 123 // ok! If the type of the generic is unknown, it's recommended to cast `ref` to `Ref`: -```js +```ts function useState(initial: State) { const state = ref(initial) as Ref // state.value -> State extends string return state @@ -49,7 +49,7 @@ function useState(initial: State) { Returns the inner value if the argument is a [`ref`](#ref), otherwise return the argument itself. This is a sugar function for `val = isRef(val) ? val.value : val`. -```js +```ts function useFoo(x: number | Ref) { const unwrapped = unref(x) // unwrapped is guaranteed to be number now } @@ -84,6 +84,8 @@ export default { } ``` +`toRef` will return a usable ref even if the source property doesn't currently exist. This makes it especially useful when working with optional props, which wouldn't be picked up by [`toRefs`](#torefs). + ## `toRefs` Converts a reactive object to a plain object where each property of the resulting object is a [`ref`](#ref) pointing to the corresponding property of the original object. @@ -140,6 +142,8 @@ export default { } ``` +`toRefs` will only generate refs for properties that are included in the source object. To create a ref for a specific property use [`toRef`](#toref) instead. + ## `isRef` Checks if a value is a ref object. @@ -213,7 +217,7 @@ isReactive(foo.value) // false ## `triggerRef` -Execute any effects tied to a [`shallowRef`](#shallowref) manually. +Execute any effects tied to a [`shallowRef`](#shallowref) manually. ```js const shallow = shallowRef({