Skip to content

Commit 253a2ae

Browse files
committed
adjust reactivity details
1 parent ce762fa commit 253a2ae

File tree

1 file changed

+40
-17
lines changed

1 file changed

+40
-17
lines changed

src/guide/essentials/reactivity-fundamentals.md

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,19 @@ It is possible to add a new property directly to the component instance without
4545

4646
Vue uses a `$` prefix when exposing its own built-in APIs via the component instance. It also reserves the prefix `_` for internal properties. You should avoid using names for top-level `data` properties that start with either of these characters.
4747

48+
### Reactive Proxy vs. Original \*
49+
50+
In Vue 3, data is made reactive by leveraging [JavaScript Proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy). Users coming from Vue 2 should be aware of the following edge case:
51+
52+
```js
53+
const object = {}
54+
this.someObject = object
55+
56+
console.log(object === this.someObject) // false
57+
```
58+
59+
When you access `this.someObject` after assigning it, the value is a reactive proxy of the original `object`. **Unlike in Vue 2, the original `object` is left intact and will not be made reactive: make sure to always access reactive state as a property of `this`.**
60+
4861
</div>
4962

5063
<div class="composition-api">
@@ -111,7 +124,7 @@ Exposed methods are typically used as event listeners:
111124
</button>
112125
```
113126

114-
### `<script setup>` **
127+
### `<script setup>` \*\*
115128

116129
Manually exposing state and methods via `setup()` can be verbose. Luckily, it is only necessary when not using a build step. When using Single File Components (SFCs), we can greatly simplify the usage with `<script setup>`:
117130

@@ -233,32 +246,38 @@ It is also possible to explicitly create [shallow refs](/api/reactivity-advanced
233246

234247
### Reactive Proxy vs. Original \*\*
235248

236-
Calling `reactive()` on the same object always returns the same proxy, and calling `reactive()` on an existing proxy also returns that same proxy:
249+
It is important to note that the returned value from `reactive()` is a [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) of the original object, which is not equal to the original object:
237250

238251
```js
239-
const raw = { count: 0, nested: {} }
252+
const raw = {}
240253
const proxy = reactive(raw)
241254

242255
// proxy is NOT equal to the original.
243256
console.log(proxy === raw) // false
257+
```
258+
259+
Only the proxy is reactive - mutating the original object will not trigger updates. Therefore, the best practice when working with Vue's reactivity system is to **exclusively use the proxied versions of your state**.
244260

245-
console.log(proxy === reactive(raw)) // true
246-
console.log(proxy === reactive(proxy)) // true
261+
To ensure consistent access to the proxy, calling `reactive()` on the same object always returns the same proxy, and calling `reactive()` on an existing proxy also returns that same proxy:
247262

248-
// nested objects in a proxy are also proxies
249-
console.log(proxy.nested === reactive(proxy.nested)) // true
263+
```js
264+
// calling reactive() on the same object returns the same proxy
265+
console.log(reactive(raw) === proxy) // true
266+
267+
// calling reactive() on a proxy returns itself
268+
console.log(reactive(proxy) === proxy) // true
250269
```
251270

252-
When you create a ref with object value, it also implicitly converts the value to a proxy using `reactive()`:
271+
This rule applies to nested objects as well. Due to deep reactivity, nested objects inside a reactive object are also proxies:
253272

254273
```js
255-
const objRef = ref(raw)
256-
console.log(objRef.value === proxy) // true
257-
```
274+
const proxy = reactive({})
258275

259-
:::tip
260-
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**.
261-
:::
276+
const raw = {}
277+
proxy.nested = raw
278+
279+
console.log(proxy.nested === raw) // false
280+
```
262281

263282
### Limitations of `reactive()` \*\*
264283

@@ -287,6 +306,8 @@ The `reactive()` API has two limitations:
287306
// count is a plain number that is disconnected
288307
// from state.count.
289308
let { count } = state
309+
// does not affect original state
310+
count++
290311
```
291312

292313
## Reactive Variables with `ref()` \*\*
@@ -341,7 +362,7 @@ const { foo, bar } = obj
341362

342363
In other words, `ref()` allows us to create a "reference" to any value and pass it around without losing reactivity. This capability is quite important as it is frequently used when extracting logic into [Composable Functions](/guide/reusability/composables.html).
343364

344-
### Ref Unwrapping in Templates **
365+
### Ref Unwrapping in Templates \*\*
345366

346367
When refs are exposed to templates and accessed on the render context, they are automatically "unwrapped" so there is no need to use `.value`. Here's the previous counter example, using `ref()` instead:
347368

@@ -365,7 +386,7 @@ function increment() {
365386

366387
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cD5cbmltcG9ydCB7IHJlZiB9IGZyb20gJ3Z1ZSdcblxuY29uc3QgY291bnQgPSByZWYoMClcblxuZnVuY3Rpb24gaW5jcmVtZW50KCkge1xuICBjb3VudC52YWx1ZSsrXG59XG48L3NjcmlwdD5cblxuPHRlbXBsYXRlPlxuICA8YnV0dG9uIEBjbGljaz1cImluY3JlbWVudFwiPnt7IGNvdW50IH19PC9idXR0b24+XG48L3RlbXBsYXRlPiIsImltcG9ydC1tYXAuanNvbiI6IntcbiAgXCJpbXBvcnRzXCI6IHtcbiAgICBcInZ1ZVwiOiBcImh0dHBzOi8vc2ZjLnZ1ZWpzLm9yZy92dWUucnVudGltZS5lc20tYnJvd3Nlci5qc1wiXG4gIH1cbn0ifQ==)
367388

368-
### Ref Unwrapping in Reactive Objects **
389+
### Ref Unwrapping in Reactive Objects \*\*
369390

370391
When a `ref` is accessed or mutated as a property of a reactive object, it is also automatically unwrapped so it behaves like a normal property:
371392

@@ -392,7 +413,9 @@ console.log(state.count) // 2
392413
console.log(count.value) // 1
393414
```
394415

395-
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`:
416+
Ref unwrapping only happens when nested inside a deep reactive object. It does not apply when it is accessed as a property of a [shallow reactive object](/api/reactivity-advanced.html#shallowreactive).
417+
418+
In addition, there is no unwrapping performed when the ref is accessed from an array or a native collection type like `Map`:
396419

397420
```js
398421
const books = reactive([ref('Vue 3 Guide')])

0 commit comments

Comments
 (0)