Skip to content

Commit 189453f

Browse files
Composition API reference (#97)
* feat: added composition API reference * fix: changed define component link * Update src/api/composition-api.md Co-authored-by: Rahul Kadyan <hi@znck.me> * Update src/api/composition-api.md Co-authored-by: Rahul Kadyan <hi@znck.me> * feat: added composition API reference * fix: changed define component link * fix: move arguments above usecases * feat: added example for attrs destructuring * fix: fixed `this` usage explanation * feat: added explanation about inline event handler * fix: added example to `isReactive` * fix: grammar * fix: grammar * fix: removed raw values mention * Addressed reviewers comments * feat: moved reactivity APIs * feat: moved reactivity utilities * feat: separated advanced reactivity apis * fix: fixed indentation * fix: refactored reactivity API structure * feat: added links to composition API * fix: renamed proxy APIs to basic * fix: fixed reactive typing * fix: addressed reviewers comments * fix: added async onInvalidate * feat: added example for generic with unknown type * fix: fixed cleanup example * fix: removed warning Co-authored-by: Rahul Kadyan <hi@znck.me>
1 parent 9efd692 commit 189453f

File tree

5 files changed

+1159
-4
lines changed

5 files changed

+1159
-4
lines changed

src/.vuepress/config.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,20 @@ const sidebar = {
8080
'/api/options-misc'
8181
]
8282
},
83-
'/api/instance-properties.md',
84-
'/api/instance-methods.md',
85-
'/api/directives.md',
86-
'/api/special-attributes.md'
83+
'/api/instance-properties',
84+
'/api/instance-methods',
85+
'/api/directives',
86+
'/api/special-attributes',
87+
{
88+
title: 'Reactivity API',
89+
collapsable: false,
90+
children: [
91+
'/api/basic-reactivity',
92+
'/api/refs-api',
93+
'/api/computed-watch-api'
94+
]
95+
},
96+
'/api/composition-api'
8797
]
8898
}
8999

src/api/basic-reactivity.md

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
# Basic Reactivity APIs
2+
3+
> This section uses [single-file component](TODO: SFC) syntax for code examples
4+
5+
## `reactive`
6+
7+
Returns a reactive copy of the object.
8+
9+
```js
10+
const obj = reactive({ count: 0 })
11+
```
12+
13+
The reactive conversion is "deep"—it affects all nested properties. In the [ES2015 Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) based implementation, the returned proxy is **not** equal to the original object. It is recommended to work exclusively with the reactive proxy and avoid relying on the original object.
14+
15+
### Typing
16+
17+
```ts
18+
function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
19+
```
20+
21+
## `readonly`
22+
23+
Takes an object (reactive or plain) or a [ref](./refs-api.html#ref) and returns a readonly proxy to the original. A readonly proxy is deep: any nested property accessed will be readonly as well.
24+
25+
```js
26+
const original = reactive({ count: 0 })
27+
28+
const copy = readonly(original)
29+
30+
watchEffect(() => {
31+
// works for reactivity tracking
32+
console.log(copy.count)
33+
})
34+
35+
// mutating original will trigger watchers relying on the copy
36+
original.count++
37+
38+
// mutating the copy will fail and result in a warning
39+
copy.count++ // warning!
40+
```
41+
42+
## `isProxy`
43+
44+
Checks if an object is a proxy created by [`reactive`](#reactive) or [`readonly`](#readonly).
45+
46+
## `isReactive`
47+
48+
Checks if an object is a reactive proxy created by [`reactive`](#reactive).
49+
50+
```js
51+
import { reactive, isReactive } from 'vue'
52+
export default {
53+
setup() {
54+
const state = reactive({
55+
name: 'John'
56+
})
57+
console.log(isReactive(state)) // -> true
58+
}
59+
}
60+
```
61+
62+
It also returns `true` if the proxy is created by [`readonly`](#readonly), but is wrapping another proxy created by [`reactive`](#reactive).
63+
64+
```js{7-15}
65+
import { reactive, isReactive, readonly } from 'vue'
66+
export default {
67+
setup() {
68+
const state = reactive({
69+
name: 'John'
70+
})
71+
// readonly proxy created from plain object
72+
const plain = readonly({
73+
name: 'Mary'
74+
})
75+
console.log(isReactive(plain)) // -> false
76+
77+
// readonly proxy created from reactive proxy
78+
const stateCopy = readonly(state)
79+
console.log(isReactive(stateCopy)) // -> true
80+
}
81+
}
82+
```
83+
84+
## `isReadonly`
85+
86+
Checks if an object is a readonly proxy created by [`readonly`](#readonly).
87+
88+
## `toRaw`
89+
90+
Returns the raw, original object of a [`reactive`](#reactive) or [`readonly`](#readonly) proxy. This is an escape hatch that can be used to temporarily read without incurring proxy access/tracking overhead or write without triggering changes. It is **not** recommended to hold a persistent reference to the original object. Use with caution.
91+
92+
```js
93+
const foo = {}
94+
const reactiveFoo = reactive(foo)
95+
96+
console.log(toRaw(reactiveFoo) === foo) // true
97+
```
98+
99+
## `markRaw`
100+
101+
Marks an object so that it will never be converted to a proxy. Returns the object itself.
102+
103+
```js
104+
const foo = markRaw({})
105+
console.log(isReactive(reactive(foo))) // false
106+
107+
// also works when nested inside other reactive objects
108+
const bar = reactive({ foo })
109+
console.log(isReactive(bar.foo)) // false
110+
```
111+
112+
::: warning
113+
`markRaw` and the shallowXXX APIs below allow you to selectively opt-out of the default deep reactive/readonly conversion and embed raw, non-proxied objects in your state graph. They can be used for various reasons:
114+
115+
- Some values simply should not be made reactive, for example a complex 3rd party class instance, or a Vue component object.
116+
117+
- Skipping proxy conversion can provide performance improvements when rendering large lists with immutable data sources.
118+
119+
They are considered advanced because the raw opt-out is only at the root level, so if you set a nested, non-marked raw object into a reactive object and then access it again, you get the proxied version back. This can lead to **identity hazards** - i.e. performing an operation that relies on object identity but using both the raw and the proxied version of the same object:
120+
121+
```js
122+
const foo = markRaw({
123+
nested: {}
124+
})
125+
126+
const bar = reactive({
127+
// although `foo` is marked as raw, foo.nested is not.
128+
nested: foo.nested
129+
})
130+
131+
console.log(foo.nested === bar.nested) // false
132+
```
133+
134+
Identity hazards are in general rare. However, to properly utilize these APIs while safely avoiding identity hazards requires a solid understanding of how the reactivity system works.
135+
:::
136+
137+
## `shallowReactive`
138+
139+
Creates a reactive proxy that tracks reactivity of its own properties but does not perform deep reactive conversion of nested objects (exposes raw values).
140+
141+
```js
142+
const state = shallowReactive({
143+
foo: 1,
144+
nested: {
145+
bar: 2
146+
}
147+
})
148+
149+
// mutating state's own properties is reactive
150+
state.foo++
151+
// ...but does not convert nested objects
152+
isReactive(state.nested) // false
153+
state.nested.bar++ // non-reactive
154+
```
155+
156+
## `shallowReadonly`
157+
158+
Creates a proxy that makes its own properties readonly, but does not perform deep readonly conversion of nested objects (exposes raw values).
159+
160+
```js
161+
const state = shallowReadonly({
162+
foo: 1,
163+
nested: {
164+
bar: 2
165+
}
166+
})
167+
168+
// mutating state's own properties will fail
169+
state.foo++
170+
// ...but works on nested objects
171+
isReadonly(state.nested) // false
172+
state.nested.bar++ // works
173+
```

0 commit comments

Comments
 (0)