Skip to content

Commit 1bd5ef8

Browse files
Migrate instance methods API (#78)
* feat: added watch * feat: added instance methods * feat: added explanation on Object watcher * fix: fixed headers
1 parent 1177278 commit 1bd5ef8

File tree

6 files changed

+284
-6
lines changed

6 files changed

+284
-6
lines changed

src/.vuepress/config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ const sidebar = {
6969
'/api/options-misc'
7070
]
7171
},
72-
'/api/instance-properties.md'
72+
'/api/instance-properties.md',
73+
'/api/instance-methods.md'
7374
]
7475
}
7576

src/api/instance-methods.md

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
# Instance Methods
2+
3+
## $watch
4+
5+
- **Arguments:**
6+
7+
- `{string | Function} source`
8+
- `{Function | Object} callback`
9+
- `{Object} [options]`
10+
- `{boolean} deep`
11+
- `{boolean} immediate`
12+
13+
- **Returns:** `{Function} unwatch`
14+
15+
- **Usage:**
16+
17+
Watch an expression or a computed function on the Vue instance for changes. The callback gets called with the new value and the old value. The expression only accepts dot-delimited paths. For more complex expressions, use a function instead.
18+
19+
- **Example:**
20+
21+
```js
22+
const app = Vue.createApp({
23+
data() {
24+
return {
25+
a: 1,
26+
b: 2
27+
}
28+
},
29+
created() {
30+
// keypath
31+
this.$watch('a', (newVal, oldVal) => {
32+
// do something
33+
})
34+
35+
// function
36+
this.$watch(
37+
// every time the expression `this.a + this.b` yields a different result,
38+
// the handler will be called. It's as if we were watching a computed
39+
// property without defining the computed property itself
40+
() => this.a + this.b,
41+
(newVal, oldVal) => {
42+
// do something
43+
}
44+
)
45+
}
46+
})
47+
```
48+
49+
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:
50+
51+
```js
52+
const app = Vue.createApp({
53+
data() {
54+
return {
55+
article: {
56+
text: 'Vue is awesome!'
57+
},
58+
comments: ['Indeed!', 'I agree']
59+
}
60+
},
61+
created() {
62+
this.$watch('article', () => {
63+
console.log('Article changed!')
64+
})
65+
66+
this.$watch('comments', () => {
67+
console.log('Comments changed!')
68+
})
69+
},
70+
methods: {
71+
// These methods won't trigger a watcher because we changed only a property of Object/Array,
72+
// not the Object/Array itself
73+
changeArticleText() {
74+
this.article.text = 'Vue 3 is awesome'
75+
},
76+
addComment() {
77+
this.comments.push('New comment')
78+
},
79+
80+
// These methods will trigger a watcher because we replaced Object/Array completely
81+
changeWholeArticle() {
82+
this.article = { text: 'Vue 3 is awesome' }
83+
},
84+
clearComments() {
85+
this.comments = []
86+
}
87+
}
88+
})
89+
```
90+
91+
`$watch` returns an unwatch function that stops firing the callback:
92+
93+
```js
94+
const app = Vue.createApp({
95+
data() {
96+
return {
97+
a: 1
98+
}
99+
}
100+
})
101+
102+
const vm = app.mount('#app')
103+
104+
const unwatch = vm.$watch('a', cb)
105+
// later, teardown the watcher
106+
unwatch()
107+
```
108+
109+
- **Option: deep**
110+
111+
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.
112+
113+
```js
114+
vm.$watch('someObject', callback, {
115+
deep: true
116+
})
117+
vm.someObject.nestedValue = 123
118+
// callback is fired
119+
```
120+
121+
- **Option: immediate**
122+
123+
Passing in `immediate: true` in the option will trigger the callback immediately with the current value of the expression:
124+
125+
```js
126+
vm.$watch('a', callback, {
127+
immediate: true
128+
})
129+
// `callback` is fired immediately with current value of `a`
130+
```
131+
132+
Note that with `immediate` option you won't be able to unwatch the given property on the first callback call.
133+
134+
```js
135+
// This will cause an error
136+
const unwatch = vm.$watch(
137+
'value',
138+
function() {
139+
doSomething()
140+
unwatch()
141+
},
142+
{ immediate: true }
143+
)
144+
```
145+
146+
If you still want to call an unwatch function inside the callback, you should check its availability first:
147+
148+
```js
149+
const unwatch = vm.$watch(
150+
'value',
151+
function() {
152+
doSomething()
153+
if (unwatch) {
154+
unwatch()
155+
}
156+
},
157+
{ immediate: true }
158+
)
159+
```
160+
161+
- **See also:** [Watchers](../guide/computed.html#watchers)
162+
163+
## $emit
164+
165+
- **Arguments:**
166+
167+
- `{string} eventName`
168+
- `[...args]`
169+
170+
Trigger an event on the current instance. Any additional arguments will be passed into the listener's callback function.
171+
172+
- **Examples:**
173+
174+
Using `$emit` with only an event name:
175+
176+
```html
177+
<div id="emit-example-simple">
178+
<welcome-button v-on:welcome="sayHi"></welcome-button>
179+
</div>
180+
```
181+
182+
```js
183+
const app = Vue.createApp({
184+
methods: {
185+
sayHi() {
186+
console.log('Hi!')
187+
}
188+
}
189+
})
190+
191+
app.component('welcome-button', {
192+
template: `
193+
<button v-on:click="$emit('welcome')">
194+
Click me to be welcomed
195+
</button>
196+
`
197+
})
198+
199+
app.mount('#emit-example-simple')
200+
```
201+
202+
Using `$emit` with additional arguments:
203+
204+
```html
205+
<div id="emit-example-argument">
206+
<advice-component v-on:give-advice="showAdvice"></advice-component>
207+
</div>
208+
```
209+
210+
```js
211+
const app = Vue.createApp({
212+
methods: {
213+
showAdvice(advice) {
214+
alert(advice)
215+
}
216+
}
217+
})
218+
219+
app.component('advice-component', {
220+
data() {
221+
return {
222+
adviceText: 'Some advice'
223+
}
224+
},
225+
template: `
226+
<div>
227+
<input type="text" v-model="adviceText">
228+
<button v-on:click="$emit('give-advice', adviceText)">
229+
Click me for sending advice
230+
</button>
231+
</div>
232+
`
233+
})
234+
```
235+
236+
- **See also:**
237+
- [`emits` option](./options-data.html#emits)
238+
- [Emitting a Value With an Event](../guide/component-basics.html#emitting-a-value-with-an-event)
239+
240+
## $forceUpdate
241+
242+
- **Usage:**
243+
244+
Force the Vue instance to re-render. Note it does not affect all child components, only the instance itself and child components with inserted slot content.
245+
246+
## $nextTick
247+
248+
- **Arguments:**
249+
250+
- `{Function} [callback]`
251+
252+
- **Usage:**
253+
254+
Defer the callback to be executed after the next DOM update cycle. Use it immediately after you've changed some data to wait for the DOM update. This is the same as the global `Vue.nextTick`, except that the callback's `this` context is automatically bound to the instance calling this method.
255+
256+
- **Example:**
257+
258+
```js
259+
Vue.createApp({
260+
// ...
261+
methods: {
262+
// ...
263+
example() {
264+
// modify data
265+
this.message = 'changed'
266+
// DOM is not updated yet
267+
this.$nextTick(function() {
268+
// DOM is now updated
269+
// `this` is bound to the current instance
270+
this.doSomethingElse()
271+
})
272+
}
273+
}
274+
})
275+
```
276+
277+
- **See also:** [Vue.nextTick](TODO)

src/api/options-lifecycle-hooks.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ All lifecycle hooks automatically have their `this` context bound to the instanc
4444

4545
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.
4646

47-
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](TODO) inside of `mounted`:
47+
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`:
4848

4949
```js
5050
mounted() {
@@ -81,7 +81,7 @@ All lifecycle hooks automatically have their `this` context bound to the instanc
8181

8282
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.
8383

84-
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](TODO) inside of `updated`:
84+
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`:
8585

8686
```js
8787
updated() {

src/guide/component-basics.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ When we click on the button, we need to communicate to the parent that it should
226226
<blog-post ... v-on:enlarge-text="postFontSize += 0.1"></blog-post>
227227
```
228228

229-
Then the child component can emit an event on itself by calling the built-in [**`$emit`** method](TODO:../api/#vm-emit), passing the name of the event:
229+
Then the child component can emit an event on itself by calling the built-in [**`$emit`** method](../api/instance-methods.html#emit), passing the name of the event:
230230

231231
```html
232232
<button v-on:click="$emit('enlarge-text')">

src/guide/computed.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ Result:
190190

191191
In this case, using the `watch` option allows us to perform an asynchronous operation (accessing an API) and sets a condition for performing this operation. None of that would be possible with a computed property.
192192

193-
In addition to the `watch` option, you can also use the imperative [vm.\$watch API](TODO:../api/#vm-watch).
193+
In addition to the `watch` option, you can also use the imperative [vm.$watch API](../api/instance-methods.html#watch).
194194

195195
### Computed vs Watched Property
196196

src/guide/instance.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ const vm = Vue.createApp().mount(
119119
vm.$data.a // => 1
120120
```
121121

122-
In the future, you can consult the [API reference](TODO:../api/#Instance-Properties) for a full list of instance properties and methods.
122+
In the future, you can consult the [API reference](../api/instance-properties.html) for a full list of instance properties and methods.
123123

124124
## Instance Lifecycle Hooks
125125

0 commit comments

Comments
 (0)