You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/guide/essentials/reactivity-fundamentals.md
+40-17Lines changed: 40 additions & 17 deletions
Original file line number
Diff line number
Diff line change
@@ -45,6 +45,19 @@ It is possible to add a new property directly to the component instance without
45
45
46
46
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.
47
47
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
+
constobject= {}
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
+
48
61
</div>
49
62
50
63
<divclass="composition-api">
@@ -111,7 +124,7 @@ Exposed methods are typically used as event listeners:
111
124
</button>
112
125
```
113
126
114
-
### `<script setup>`**
127
+
### `<script setup>`\*\*
115
128
116
129
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>`:
117
130
@@ -233,32 +246,38 @@ It is also possible to explicitly create [shallow refs](/api/reactivity-advanced
233
246
234
247
### Reactive Proxy vs. Original \*\*
235
248
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:
237
250
238
251
```js
239
-
constraw= { count:0, nested: {} }
252
+
constraw= {}
240
253
constproxy=reactive(raw)
241
254
242
255
// proxy is NOT equal to the original.
243
256
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**.
244
260
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:
// 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
250
269
```
251
270
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:
253
272
254
273
```js
255
-
constobjRef=ref(raw)
256
-
console.log(objRef.value=== proxy) // true
257
-
```
274
+
constproxy=reactive({})
258
275
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
+
constraw= {}
277
+
proxy.nested= raw
278
+
279
+
console.log(proxy.nested=== raw) // false
280
+
```
262
281
263
282
### Limitations of `reactive()`\*\*
264
283
@@ -287,6 +306,8 @@ The `reactive()` API has two limitations:
287
306
// count is a plain number that is disconnected
288
307
// from state.count.
289
308
let { count } = state
309
+
// does not affect original state
310
+
count++
290
311
```
291
312
292
313
## Reactive Variables with `ref()`\*\*
@@ -341,7 +362,7 @@ const { foo, bar } = obj
341
362
342
363
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).
343
364
344
-
### Ref Unwrapping in Templates **
365
+
### Ref Unwrapping in Templates \*\*
345
366
346
367
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:
347
368
@@ -365,7 +386,7 @@ function increment() {
365
386
366
387
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cD5cbmltcG9ydCB7IHJlZiB9IGZyb20gJ3Z1ZSdcblxuY29uc3QgY291bnQgPSByZWYoMClcblxuZnVuY3Rpb24gaW5jcmVtZW50KCkge1xuICBjb3VudC52YWx1ZSsrXG59XG48L3NjcmlwdD5cblxuPHRlbXBsYXRlPlxuICA8YnV0dG9uIEBjbGljaz1cImluY3JlbWVudFwiPnt7IGNvdW50IH19PC9idXR0b24+XG48L3RlbXBsYXRlPiIsImltcG9ydC1tYXAuanNvbiI6IntcbiAgXCJpbXBvcnRzXCI6IHtcbiAgICBcInZ1ZVwiOiBcImh0dHBzOi8vc2ZjLnZ1ZWpzLm9yZy92dWUucnVudGltZS5lc20tYnJvd3Nlci5qc1wiXG4gIH1cbn0ifQ==)
367
388
368
-
### Ref Unwrapping in Reactive Objects **
389
+
### Ref Unwrapping in Reactive Objects \*\*
369
390
370
391
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:
371
392
@@ -392,7 +413,9 @@ console.log(state.count) // 2
392
413
console.log(count.value) // 1
393
414
```
394
415
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`:
0 commit comments