Skip to content

Commit d43fd69

Browse files
committed
more reactivity
1 parent 2cea411 commit d43fd69

File tree

2 files changed

+137
-54
lines changed

2 files changed

+137
-54
lines changed

src/guide/essentials/basic-reactivity.md

Lines changed: 118 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ With Options API, we use the `data` option to declare reactive state of a compon
1414
export default {
1515
data() {
1616
return {
17-
count: 1
17+
count: 0
1818
}
1919
},
2020

@@ -159,10 +159,10 @@ Top-level imports and variables declared in `<script setup>` are automatically u
159159
To add methods to a component instance we use the `methods` option. This should be an object containing the desired methods:
160160

161161
```js
162-
const app = Vue.createApp({
162+
export default {
163163
data() {
164164
return {
165-
count: 4
165+
count: 0
166166
}
167167
},
168168
methods: {
@@ -174,20 +174,77 @@ const app = Vue.createApp({
174174
// methods can be called in lifecycle hooks, or other methods!
175175
this.increment()
176176
}
177-
})
177+
}
178178
```
179179

180+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdD5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgZGF0YSgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgY291bnQ6IDBcbiAgICB9XG4gIH0sXG4gIG1ldGhvZHM6IHtcbiAgICBpbmNyZW1lbnQoKSB7XG4gICAgICB0aGlzLmNvdW50KytcbiAgICB9XG4gIH0sXG4gIG1vdW50ZWQoKSB7XG4gICAgdGhpcy5pbmNyZW1lbnQoKVxuICB9XG59XG48L3NjcmlwdD5cblxuPHRlbXBsYXRlPlxuICA8YnV0dG9uIEBjbGljaz1cImluY3JlbWVudFwiPnt7IGNvdW50IH19PC9idXR0b24+XG48L3RlbXBsYXRlPiIsImltcG9ydC1tYXAuanNvbiI6IntcbiAgXCJpbXBvcnRzXCI6IHtcbiAgICBcInZ1ZVwiOiBcImh0dHBzOi8vc2ZjLnZ1ZWpzLm9yZy92dWUucnVudGltZS5lc20tYnJvd3Nlci5qc1wiXG4gIH1cbn0ifQ==)
181+
180182
Vue automatically binds the `this` value for `methods` so that it always refers to the component instance. This ensures that a method retains the correct `this` value if it's used as an event listener or callback. You should avoid using arrow functions when defining `methods`, as that prevents Vue from binding the appropriate `this` value.
181183

182184
Just like all other properties of the component instance, the `methods` are accessible from within the component's template. Inside a template they are most commonly used as event listeners:
183185

184186
```vue-html
185-
<button @click="increment">Up vote</button>
187+
<button @click="increment">{{ count }}</button>
186188
```
187189

188190
In the example above, the method `increment` will be called when the `<button>` is clicked.
189191

190-
It is also possible to call a method directly from a template. As we'll see shortly, it's usually better to use a [computed property](computed.html) instead. However, using a method can be useful in scenarios where computed properties aren't a viable option. You can call a method anywhere that a template supports JavaScript expressions:
192+
</div>
193+
194+
<div class="composition-api">
195+
196+
To declare methods when using Composition API, simply declare functions in the same scope with the reactive state:
197+
198+
```js
199+
import { ref } from 'vue'
200+
201+
export default {
202+
setup() {
203+
const count = ref(0)
204+
205+
function increment() {
206+
count.value++
207+
}
208+
209+
// when using manual setup(),
210+
// don't forget to expose the function as well.
211+
return {
212+
count,
213+
increment
214+
}
215+
}
216+
}
217+
```
218+
219+
Methods are typically used as event listeners:
220+
221+
```vue-html
222+
<button @click="increment">{{ count }}</button>
223+
```
224+
225+
Again, the same example is much simpler in an SFC with `<script setup>`, as functions are auto-exposes as well:
226+
227+
```vue
228+
<script setup>
229+
import { ref } from 'vue'
230+
231+
const count = ref(0)
232+
233+
function increment() {
234+
count.value++
235+
}
236+
</script>
237+
238+
<template>
239+
<button @click="increment">{{ count }}</button>
240+
</template>
241+
```
242+
243+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cD5cbmltcG9ydCB7IHJlZiB9IGZyb20gJ3Z1ZSdcblxuY29uc3QgY291bnQgPSByZWYoMClcblxuZnVuY3Rpb24gaW5jcmVtZW50KCkge1xuICBjb3VudC52YWx1ZSsrXG59XG48L3NjcmlwdD5cblxuPHRlbXBsYXRlPlxuICA8YnV0dG9uIEBjbGljaz1cImluY3JlbWVudFwiPnt7IGNvdW50IH19PC9idXR0b24+XG48L3RlbXBsYXRlPiIsImltcG9ydC1tYXAuanNvbiI6IntcbiAgXCJpbXBvcnRzXCI6IHtcbiAgICBcInZ1ZVwiOiBcImh0dHBzOi8vc2ZjLnZ1ZWpzLm9yZy92dWUucnVudGltZS5lc20tYnJvd3Nlci5qc1wiXG4gIH1cbn0ifQ==)
244+
245+
</div>
246+
247+
It is also possible to call a method inside a binding expression. As we'll see shortly, it's usually better to use a [computed property](computed.html) instead. However, using a method can be useful in scenarios where computed properties aren't a viable option. You can call a method anywhere that a template supports JavaScript expressions:
191248

192249
```vue-html
193250
<span :title="toTitleDate(date)">
@@ -199,6 +256,59 @@ If the methods `toTitleDate` or `formatDate` access any reactive data then it wi
199256

200257
Methods called inside binding expressions should **not** have any side effects, such as changing data or triggering asynchronous operations. If you find yourself tempted to do that you should probably use a [lifecycle hook](/guide/components/lifecycle.html) instead.
201258

259+
### Deep Reactivity
260+
261+
In Vue, state is deeply reactive by default. This means you can expect changes to be detected even when you mutate nested objects or arrays:
262+
263+
<div class="options-api">
264+
265+
```js
266+
export default {
267+
data() {
268+
return {
269+
obj: {
270+
nested: { count: 0 },
271+
arr: ['foo', 'bar']
272+
}
273+
}
274+
},
275+
methods: {
276+
mutateDeeply() {
277+
// these will work as expected.
278+
this.obj.nested.count++
279+
this.obj.arr.push('baz')
280+
}
281+
}
282+
}
283+
```
284+
285+
</div>
286+
287+
<div class="composition-api">
288+
289+
```vue
290+
<script setup>
291+
import { ref } from 'vue'
292+
293+
const obj = ref({
294+
nested: { count: 0 },
295+
arr: ['foo', 'bar']
296+
})
297+
298+
function mutateDeeply() {
299+
// these will work as expected.
300+
obj.value.nested.count++
301+
obj.value.arr.push('baz')
302+
}
303+
</script>
304+
```
305+
306+
</div>
307+
308+
It is also possible to explicitly create ["shallow" reactive objects](/guide/advanced/reactivity-in-depth.html#deep-vs-shallow-reactivity) where the reactivity is only tracked for root-level properties, however they are typically only needed in advanced use cases.
309+
310+
<div class="options-api">
311+
202312
### Debouncing and Throttling
203313

204314
Vue doesn't include built-in support for debouncing or throttling but it can be implemented using libraries such as [Lodash](https://lodash.com/).
@@ -251,53 +361,6 @@ app.component('save-button', {
251361

252362
<div class="composition-api">
253363

254-
To declare methods when using Composition API, simply declare functions in the same scope with the reactive state:
255-
256-
```js
257-
import { ref } from 'vue'
258-
259-
export default {
260-
setup() {
261-
const count = ref(0)
262-
263-
function increment() {
264-
count.value++
265-
}
266-
267-
// when using manual setup(),
268-
// don't forget to expose the function as well.
269-
return {
270-
count,
271-
increment
272-
}
273-
}
274-
}
275-
```
276-
277-
```html
278-
<button @click="increment">{{ count }}</button>
279-
```
280-
281-
Again, it's much simpler with `<script setup>` as it auto-exposes functions as well:
282-
283-
```vue
284-
<script setup>
285-
import { ref } from 'vue'
286-
287-
const count = ref(0)
288-
289-
function increment() {
290-
count.value++
291-
}
292-
</script>
293-
294-
<template>
295-
<button @click="increment">{{ count }}</button>
296-
</template>
297-
```
298-
299-
</div>
300-
301364
### Ref Transform
302365

303366
The necessity of using `.value` wit refs roots from the language constraints of JavaScript. However, with compile-time transforms we can improve the ergonomics by automatically appending `.value` in appropriate locations. The [ref transform](https://github.com/vuejs/vue-next/tree/master/packages/ref-transform) allows us to write the above example like this:
@@ -319,3 +382,5 @@ function increment() {
319382
:::warning Experimental
320383
Ref transform is currently an experimental feature. It is disabled by default and requires explicit opt-in. It may also change before being finalized. More details can be found in its [proposal and discussion on GitHub](https://github.com/vuejs/rfcs/discussions/369).
321384
:::
385+
386+
</div>

src/guide/essentials/computed.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44

55
In-template expressions are very convenient, but they are meant for simple operations. Putting too much logic in your templates can make them bloated and hard to maintain. For example, if we have an object with a nested array:
66

7+
<div class="options-api">
8+
79
```js
8-
Vue.createApp({
10+
export default {
911
data() {
1012
return {
1113
author: {
@@ -18,9 +20,25 @@ Vue.createApp({
1820
}
1921
}
2022
}
23+
}
24+
```
25+
26+
</div>
27+
<div class="composition-api">
28+
29+
```js
30+
const author = ref({
31+
name: 'John Doe',
32+
books: [
33+
'Vue 2 - Advanced Guide',
34+
'Vue 3 - Basic Guide',
35+
'Vue 4 - The Mystery'
36+
]
2137
})
2238
```
2339

40+
</div>
41+
2442
And we want to display different messages depending on if `author` already has some books or not
2543

2644
```vue-html

0 commit comments

Comments
 (0)