Skip to content

Commit c7d1ac9

Browse files
committed
wip
1 parent d7aae8c commit c7d1ac9

File tree

2 files changed

+78
-92
lines changed

2 files changed

+78
-92
lines changed

src/guide/essentials/reactivity-fundamentals.md

Lines changed: 51 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ There are two reasons why we need to wrap the value in an object:
104104
count.value++ // this will affect the log output.
105105
```
106106

107-
This capability is quite important as it unlocks powerful patterns that allow us to compose reactive logic encapsulated in decoupled functions, which we will discuss later in the guide.
107+
This capability is quite important as it is frequently used when extracting logic into [Composable Functions](/guide/reusability/composables.html).
108108

109109
### Exposing State to Template
110110

@@ -166,14 +166,20 @@ const state = reactive({ count: 0 })
166166
</template>
167167
```
168168

169-
Reactive objects are [JavaScript Proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) and work exactly like normal objects. Calling `reactive()` on the same object always returns the same proxy, and calling `reactive()` on an existing proxy also returns that same proxy:
169+
Reactive objects are [JavaScript Proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) and behave just like normal objects. Calling `reactive()` on the same object always returns the same proxy, and calling `reactive()` on an existing proxy also returns that same proxy:
170170

171171
```js
172-
const raw = { count: 0 }
172+
const raw = { count: 0, nested: {} }
173173
const proxy = reactive(raw)
174174

175+
// proxy is NOT equal to the original.
176+
console.log(proxy === raw) // false
177+
175178
console.log(proxy === reactive(raw)) // true
176179
console.log(proxy === reactive(proxy)) // true
180+
181+
// nested objects in a proxy are also proxies
182+
console.log(proxy.nested === reactive(proxy.nested)) // true
177183
```
178184

179185
When you create a ref with object value, it also implicitly converts the value to a proxy using `reactive()`:
@@ -183,14 +189,47 @@ const objRef = ref(raw)
183189
console.log(objRef.value === proxy) // true
184190
```
185191

186-
It is important to note that the proxy is not equal to the original object. Only the proxy is reactive. Mutating the original object will not trigger reactive updates:
192+
:::tip
193+
The reactive proxy is NOT equal to the original object, and only the proxy is reactive. Mutating the original object will not trigger updates. The best practice when working with Vue's reactivity system is to **exclusively use the proxied versions of your state**.
194+
:::
195+
196+
### Ref Unwrapping in Reactive Objects
197+
198+
When a `ref` is accessed or mutated as a property of a reactive object, it automatically unwraps to the inner value so it behaves like a normal property:
199+
200+
```js
201+
const count = ref(0)
202+
const state = reactive({
203+
count
204+
})
205+
206+
console.log(state.count) // 0
207+
208+
state.count = 1
209+
console.log(count.value) // 1
210+
```
211+
212+
If a new ref is assigned to a property linked to an existing ref, it will replace the old ref:
187213

188214
```js
189-
console.log(raw === proxy) // false
190-
raw.count++ // won't trigger updates!
215+
const otherCount = ref(2)
216+
217+
state.count = otherCount
218+
console.log(state.count) // 2
219+
console.log(count.value) // 1
191220
```
192221

193-
Therefore, the best practice when working with Vue's reactivity system is to **exclusively use the proxied versions of your state**.
222+
Ref unwrapping only happens when nested inside a reactive object. There is no unwrapping performed when the ref is accessed from an array or a native collection type like [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map):
223+
224+
```js
225+
const books = reactive([ref('Vue 3 Guide')])
226+
// need .value here
227+
console.log(books[0].value)
228+
229+
const map = reactive(new Map([['count', ref(0)]]))
230+
// need .value here
231+
console.log(map.get('count').value)
232+
```
194233

195234
</div>
196235

@@ -330,24 +369,24 @@ export default {
330369

331370
```vue
332371
<script setup>
333-
import { ref } from 'vue'
372+
import { reactive } from 'vue'
334373
335-
const obj = ref({
374+
const obj = reactive({
336375
nested: { count: 0 },
337376
arr: ['foo', 'bar']
338377
})
339378
340379
function mutateDeeply() {
341380
// these will work as expected.
342-
obj.value.nested.count++
343-
obj.value.arr.push('baz')
381+
obj.nested.count++
382+
obj.arr.push('baz')
344383
}
345384
</script>
346385
```
347386

348387
</div>
349388

350-
It is also possible to explicitly create ["shallow" refs and reactive objects](/api/reactivity-advanced.html#shallowref) where the reactivity is only tracked at the root-level, however they are typically only needed in advanced use cases.
389+
It is also possible to explicitly create [shallow refs](<(/api/reactivity-advanced.html#shallowref)>) and [shallow reactive objects](/api/reactivity-advanced.html#shallowreactive) where the reactivity is only tracked at the root-level, however they are typically only needed in advanced use cases.
351390

352391
<div class="options-api">
353392

@@ -425,83 +464,4 @@ function increment() {
425464
Ref transform is currently an experimental feature. It is disabled by default and requires [explicit opt-in](https://github.com/vuejs/rfcs/blob/ref-sugar-2/active-rfcs/0000-ref-sugar.md#enabling-the-macros). 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).
426465
:::
427466

428-
## Additional Details
429-
430-
### Ref Unwrapping in Reactive Objects
431-
432-
When a `ref` is accessed or mutated as a property of a reactive object, it automatically unwraps to the inner value so it behaves like a normal property:
433-
434-
```js
435-
const count = ref(0)
436-
const state = reactive({
437-
count
438-
})
439-
440-
console.log(state.count) // 0
441-
442-
state.count = 1
443-
console.log(count.value) // 1
444-
```
445-
446-
If a new ref is assigned to a property linked to an existing ref, it will replace the old ref:
447-
448-
```js
449-
const otherCount = ref(2)
450-
451-
state.count = otherCount
452-
console.log(state.count) // 2
453-
console.log(count.value) // 1
454-
```
455-
456-
Ref unwrapping only happens when nested inside a reactive object. There is no unwrapping performed when the ref is accessed from an array or a native collection type like [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map):
457-
458-
```js
459-
const books = reactive([ref('Vue 3 Guide')])
460-
// need .value here
461-
console.log(books[0].value)
462-
463-
const map = reactive(new Map([['count', ref(0)]]))
464-
// need .value here
465-
console.log(map.get('count').value)
466-
```
467-
468-
### Destructuring Reactive Objects
469-
470-
When we want to use a few properties of the large reactive object, it could be tempting to use destructuring to get properties we want:
471-
472-
```js
473-
import { reactive } from 'vue'
474-
475-
const book = reactive({
476-
author: 'Vue Team',
477-
year: '2020',
478-
title: 'Vue 3 Guide',
479-
description: 'You are reading this book right now ;)',
480-
price: 'free'
481-
})
482-
483-
let { author, title } = book
484-
```
485-
486-
Unfortunately, with such a destructuring the reactivity for both properties would be lost. For such a case, we need to convert our reactive object to a set of refs. These refs will retain the reactive connection to the source object:
487-
488-
```js
489-
import { reactive, toRefs } from 'vue'
490-
491-
const book = reactive({
492-
author: 'Vue Team',
493-
year: '2020',
494-
title: 'Vue 3 Guide',
495-
description: 'You are reading this book right now ;)',
496-
price: 'free'
497-
})
498-
499-
let { author, title } = toRefs(book)
500-
501-
title.value = 'Vue 3 Detailed Guide' // we need to use .value as title is a ref now
502-
console.log(book.title) // 'Vue 3 Detailed Guide'
503-
```
504-
505-
You can learn more about `toRefs` in the [API Reference](/api/reactivity-utilities.html#torefs).
506-
507467
</div>

src/guide/reusability/composables.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,27 @@
1-
# Reusing Logic with Composables
1+
# Reusing Logic with Composables
2+
3+
### Retaining Reactivity
4+
5+
When we want to use a few properties of the large reactive object, it could be tempting to use destructuring to get properties we want. However, the destructured property would lose the reactivity connection to the original object:
6+
7+
```js
8+
const state = reactive({
9+
count: 0
10+
// ... with many other properties
11+
})
12+
13+
// `count` won't be reactive once destructured
14+
// as it's just a number now
15+
const { count } = state
16+
```
17+
18+
You can create a ref from a property of a reactive object with [`toRef()`](/api/reactivity-utilities.html#toref):
19+
20+
```js
21+
import { toRef } from 'vue'
22+
23+
const count = toRef(state, 'count')
24+
25+
state.count++
26+
console.log(count.value) // 1
27+
```

0 commit comments

Comments
 (0)