1、shallowReactiveとshallowRef
- ShallowReactive : オブジェクトの最も外側のプロパティの応答性 (つまり、浅い応答性) のみを処理します。
- ShallowRef: 値の応答タイプのみを処理し、オブジェクトのリアクティブ処理は実行しません。
<template>
<h2>App</h2>
<h3>m1: {
{m1}}</h3>
<h3>m2: {
{m2}}</h3>
<h3>m3: {
{m3}}</h3>
<h3>m4: {
{m4}}</h3>
<button @click="update">更新</button>
</template>
<script lang="ts">
import {
reactive, ref, shallowReactive, shallowRef } from 'vue'
/*
shallowReactive与shallowRef
shallowReactive: 只处理了对象内最外层属性的响应式(也就是浅响应式)
shallowRef: 只处理了value的响应式, 不进行对象的reactive处理
总结:
reactive与ref实现的是深度响应式, 而shallowReactive与shallowRef是浅响应式
什么时候用浅响应式呢?
一般情况下使用ref和reactive即可,
如果有一个对象数据, 结构比较深, 但变化时只是外层属性变化 ===> shallowReactive
如果有一个对象数据, 后面会产生新的对象来替换 ===> shallowRef
*/
export default {
setup () {
const m1 = reactive({
a: 1, b: {
c: 2}})
const m2 = shallowReactive({
a: 1, b: {
c: 2}})
const m3 = ref({
a: 1, b: {
c: 2}})
const m4 = shallowRef({
a: 1, b: {
c: 2}})
const update = () => {
// m1.b.c += 1
// m2.b.c += 1
// m3.value.a += 1
m4.value.a += 1
}
return {
m1,
m2,
m3,
m4,
update,
}
}
}
</script>
2、readonlyとshallowReadonly
- readonly: 深い読み取り専用データ、オブジェクト (リアクティブまたはプレーン) または ref を受け取り、元のプロキシを返す読み取り専用プロキシ、読み取り専用プロキシは深い: アクセスされるネストされたプロパティも読み取り専用です。
- shallowReadonly: 浅い読み取り専用データ。プロキシを作成して独自のプロパティを読み取り専用にしますが、ネストされたオブジェクトの深い読み取り専用変換は実行しません。
- アプリケーション シナリオ: 特定のケースでは、データを更新したくない場合があるため、データを読み取るための読み取り専用プロキシ オブジェクトをラップして生成できますが、変更や削除はできません。
<template>
<h2>App</h2>
<h3>{
{state}}</h3>
<button @click="update">更新</button>
</template>
<script lang="ts">
import {
reactive, readonly, shallowReadonly } from 'vue'
/*
readonly: 深度只读数据
获取一个对象 (响应式或纯对象) 或 ref 并返回原始代理的只读代理。
只读代理是深层的:访问的任何嵌套 property 也是只读的。
shallowReadonly: 浅只读数据
创建一个代理,使其自身的 property 为只读,但不执行嵌套对象的深度只读转换
应用场景:
在某些特定情况下, 我们可能不希望对数据进行更新的操作, 那就可以包装生成一个只读代理对象来读取数据, 而不能修改或删除
*/
export default {
setup () {
const state = reactive({
a: 1,
b: {
c: 2
}
})
// const rState1 = readonly(state)
const rState2 = shallowReadonly(state)
const update = () => {
// rState1.a++ // error
// rState1.b.c++ // error
// rState2.a++ // error
rState2.b.c++
}
return {
state,
update
}
}
}
</script>
3、toRawとmarkRaw
- toRaw: プロキシ オブジェクトを通常のオブジェクトに変換します。データが変更されてもインターフェイスは変わりません。
- markRaw: オブジェクトがプロキシに変換されず、リアクティブでなくなるようにオブジェクトをマークします。
<template>
<h2>{
{state}}</h2>
<button @click="testToRaw">测试toRaw</button>
<button @click="testMarkRaw">测试markRaw</button>
</template>
<script lang="ts">
import {
markRaw, reactive, toRaw } from 'vue'
export default {
setup () {
const state = reactive<any>({
name: 'tom',
age: 25,
})
const testToRaw = () => {
const user = toRaw(state)
user.age++ // 界面不会更新
}
const testMarkRaw = () => {
const likes = ['a', 'b']
// state.likes = likes
state.likes = markRaw(likes) // likes数组就不再是响应式的了
setTimeout(() => {
state.likes[0] += '--'
}, 1000)
}
return {
state,
testToRaw,
testMarkRaw,
}
}
}
</script>
4,参照へ
ソース応答オブジェクトのプロパティは ref オブジェクトを作成し、この 2 つは内部的に同じデータ値を操作し、更新時に 2 つが同期されます。
相違点参照:新しいデータ値をコピーして独立して動作し、更新時に相互に影響を与えません。
Application:: toRef は、prop の ref を複合関数に渡したい場合に便利です
<template>
<h2>App</h2>
<p>{
{state}}</p>
<p>{
{foo}}</p>
<p>{
{foo2}}</p>
<button @click="update">更新</button>
<Child :foo="foo"/>
</template>
<script lang="ts">
/*
toRef:
为源响应式对象上的某个属性创建一个 ref对象, 二者内部操作的是同一个数据值, 更新时二者是同步的
区别ref: 拷贝了一份新的数据值单独操作, 更新时相互不影响
应用: 当要将某个 prop 的 ref 传递给复合函数时,toRef 很有用
*/
import {
reactive, toRef, ref } from 'vue'
import Child from './Child.vue'
export default {
setup () {
const state = reactive({
foo: 1,
bar: 2
})
const foo = toRef(state, 'foo')
const foo2 = ref(state.foo)
const update = () => {
state.foo++
// foo.value++
// foo2.value++ // foo和state中的数据不会更新
}
return {
state,
foo,
foo2,
update,
}
},
components: {
Child
}
}
</script>
5.customRef の原理 -------- ref
カスタム ref を作成し、その依存関係の追跡と更新のトリガーを明示的に制御します。
コールバック関数は 2 つあり、1 つは Vue にデータの監視と追跡を指示する track() で、もう 1 つは更新をトリガーする trigger() です。
<template>
<h2>App</h2>
<input v-model="keyword" placeholder="搜索关键字"/>
<p>{
{keyword}}</p>
</template>
<script lang="ts">
/*
customRef:
创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制
需求:
使用 customRef 实现 debounce 的示例
*/
import {
ref,
customRef
} from 'vue'
export default {
setup () {
const keyword = useDebouncedRef('', 500)
console.log(keyword)
return {
keyword
}
},
}
/*
实现函数防抖的自定义ref
*/
function useDebouncedRef<T>(value: T, delay = 200) {
let timeout: number
return customRef((track, trigger) => {
return {
get() {
// 告诉Vue追踪数据
track()
return value
},
set(newValue: T) {
clearTimeout(timeout)
timeout = setTimeout(() => {
value = newValue
// 告诉Vue去触发界面更新
trigger()
}, delay)
}
}
})
}
</script>
6. 実装コンポーネント通信の提供と挿入
- Provide と inject は、依存関係の注入を提供します。これは、Vue2 の Provide/injectに似ています。
- クロスレベルコンポーネント間の通信 (祖父と孫、クロスドメインの親子コンポーネント通信、および直接の祖父母通信) を実現します。
<template>
<h1>父组件</h1>
<p>当前颜色: {
{color}}</p>
<button @click="color='red'">红</button>
<button @click="color='yellow'">黄</button>
<button @click="color='blue'">蓝</button>
<hr>
<Son />
</template>
<script lang="ts">
import {
provide, ref } from 'vue'
/*
- provide` 和 `inject` 提供依赖注入,功能类似 2.x 的 `provide/inject
- 实现跨层级组件(祖孙)间通信
*/
import Son from './Son.vue'
export default {
name: 'ProvideInject',
components: {
Son
},
setup() {
const color = ref('red')
provide('color', color)
return {
color
}
}
}
</script>
<template>
<div>
<h2>子组件</h2>
<hr>
<GrandSon />
</div>
</template>
<script lang="ts">
import GrandSon from './GrandSon.vue'
export default {
components: {
GrandSon
},
}
</script>
<template>
<h3 :style="{color}">孙子组件: {
{color}}</h3>
</template>
<script lang="ts">
import {
inject } from 'vue'
export default {
setup() {
const color = inject('color')
return {
color
}
}
}
</script>
7. レスポンシブデータの判定
- isRef: 値が ref オブジェクトかどうかを確認します。
- isReactive: オブジェクトが reactive によって作成されたリアクティブ プロキシであるかどうかを確認します。
- isReadonly: オブジェクトが readonly によって作成された読み取り専用プロキシであるかどうかを確認します。
- isProxy: オブジェクトがリアクティブ メソッドまたは読み取り専用メソッドによって作成されたプロキシであるかどうかを確認します。