Vue3知识点整理(5)- 其他Composition API

目录

一、shallowReactive 与 shallowRef

1.1 简介

1.2 简单案例练习

二、readonly 与 shallowReadonly

2.1 简介

2.2 简单案例练习

三、toRaw 与 markRaw

3.1 toRaw

3.2 markRaw

四、customRef

4.1 案例练习

五、provide 与 inject

六、响应式数据的判断


一、shallowReactive 与 shallowRef

Vue3官方文档 - shallowRef

Vue3官方文档 - shallowReactive

1.1 简介

  • shallowReactive:只处理对象最外层属性的响应式(浅响应式)
  • shallowRef:只处理基本数据类型的响应式,不进行对象的响应式处理
  • 使用场景:
    • 如果一个对象数据,结构比较深,但变化时知识外层属性变化,使用shallowReactive
    • 如果一个对象数据,后续功能不会修改该对象中的属性,而是生成新的对象来替换,使用shallowRef

1.2 简单案例练习

只允许修改name 和 age属性

<template>
  <h2>姓名:{{ name }}</h2>
  <h2>年龄:{{ age }}</h2>
  <h2>零用钱:{{ item.wallet.money }}</h2>
  <button @click="name += '!'">姓名添加上!</button>
  <button @click="age++">年龄增长</button>
  <button @click="item.wallet.money++">零花钱增加</button>
</template>

<script>
import { reactive, toRef, toRefs, shallowReactive } from "vue";
export default {
  name: "App",
  setup() {
    // 当只允许修改name和age属性时,使用shallowReactive
    let person = shallowReactive({
      name: "周星星",
      age: 25,
      item: {
        wallet: {
          money: 100,
        },
      },
    });

    return {
      ...toRefs(person),
    };
  },
};
</script>

二、readonly 与 shallowReadonly

Vue3官方文档 - readonly

Vue3官方文档 - shallowReadonly

2.1 简介

  • readonly;让一个响应式数据变为只读的(深只读)
  • shallowReadonly:让一个响应式数据变为只读的(浅只读)
  • 应用场景:不希望数据被修改时

2.2 简单案例练习

  • 将person响应式数据定义为深只读
<template>
  <h2>姓名:{{ name }}</h2>
  <h2>年龄:{{ age }}</h2>
  <h2>零用钱:{{ item.wallet.money }}</h2>
  <button @click="name += '!'">姓名添加上!</button>
  <button @click="age++">年龄增长</button>
  <button @click="item.wallet.money++">零花钱增加</button>
</template>

<script>
import { reactive, toRef, toRefs, shallowReactive } from "vue";
export default {
  name: "App",
  setup() {
    // 当只允许修改name和age属性时,使用shallowReactive
    let person = reactive({
      name: "周星星",
      age: 25,
      item: {
        wallet: {
          money: 100,
        },
      },
    });
    // 使用readonly - 深只读
    person = readonly(person);

    return {
      ...toRefs(person),
    };
  },
};
</script>

  • 将person响应式数据定义为深只读
    // 使用readonly - 深只读
    // person = readonly(person);

    // 使用shallowReadonly - 浅只读
    person = shallowReadonly(person);


三、toRaw 与 markRaw

Vue3官方文档 - toRaw

Vue3官方文档 - markRaw

3.1 toRaw

  • 作用:将一个由 reactive 生成的 响应式对象 转为 普通对象
  • 使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新

简单案例练习

<template>
  <h2>姓名:{{ name }}</h2>
  <h2>年龄:{{ age }}</h2>
  <h2>零用钱:{{ item.wallet.money }}</h2>
  <button @click="name += '!'">姓名添加上!</button>
  <button @click="age++">年龄增长</button>
  <button @click="item.wallet.money++">零花钱增加</button>
  <button @click="showRawPerson">输出最原始的pserson</button>
</template>

<script>
import { reactive, toRefs, toRaw } from "vue";
export default {
  name: "App",
  setup() {
    // 当只允许修改name和age属性时,使用shallowReactive
    let person = reactive({
      name: "周星星",
      age: 25,
      item: {
        wallet: {
          money: 100,
        },
      },
    });

    function showRawPerson() {
      const p = toRaw(person);
      p.age++;
      console.log(p);
    }

    return {
      ...toRefs(person),
      showRawPerson,
    };
  },
};
</script>

由图示可看出控制台输出了原始的person对象,且person对象内的属性发生改变时,并不会更新页面数据(即非响应式的)

3.2 markRaw

  • 作用:标记一个对象,使其永远不会再成为响应式对象
  • 应用场景:
    • 有些值不应被设置为响应式的,例如复杂的第三方类库等
    • 当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能

案例练习

  • 设置按钮以及点击事件为person对象添加game属性,并设置name 和 price
  • 设置点击事件修改name和price
  • 未使用markRaw
<template>
  <h2>姓名:{{ name }}</h2>
  <h2>年龄:{{ age }}</h2>
  <h2>零用钱:{{ item.wallet.money }}</h2>
  <h2 v-show="person.game">游戏卡带:{{ person.game }}</h2>
  <button @click="name += '!'">姓名添加上!</button>
  <button @click="age++">年龄增长</button>
  <button @click="item.wallet.money++">零花钱增加</button>
  <button @click="showRawPerson">输出最原始的pserson</button>
  <button @click="addGame">添加游戏卡带信息</button><br />
  <button v-show="person.game" @click="person.game.name += '!'">
    游戏名添加!
  </button>
  <button v-show="person.game" @click="changePrice">游戏价格上涨</button>
</template>

<script>
import { reactive, toRefs, toRaw, markRaw } from "vue";
export default {
  name: "App",
  setup() {
    // 当只允许修改name和age属性时,使用shallowReactive
    let person = reactive({
      name: "周星星",
      age: 25,
      item: {
        wallet: {
          money: 100,
        },
      },
    });

    function showRawPerson() {
      const p = toRaw(person);
      p.age++;
      console.log(p);
    }

    function addGame() {
      let game = { name: "Splatoon3", price: 199 };
      person.game = game;
    }

    function changePrice() {
      person.game.price++;
      console.log(person.game.price);
    }

    return {
      person,
      ...toRefs(person),
      showRawPerson,
      addGame,
      changePrice,
    };
  },
};
</script>

由图示可以看出来person.game内的 name 和 price 是可以被修改的,且界面会作出相应的变化,是响应式的

使用 markRaw 标记 game

    function addGame() {
      let game = { name: "Splatoon3", price: 199 };
      // person.game = game;
      person.game = markRaw(game);
    }

由图示可看出,game对象被markRaw标记后,点击修改name以及price按钮后,name属性 和 price属性在界面都未更新,而控制台上有显示price被修改的信息


四、customRef

Vue3官方文档 - customRef

作用:创建一个自定义的ref,并对其依赖项跟踪和更新触发进行显示控制

4.1 案例练习

实现防抖效果 - Vue3官方文档案例练习

首先看看无防抖效果时会出现的现象 - 点击频率超过定时器所定义的等待的毫秒数

由图示可以看到修改频率高于定时器所定义的等待的毫秒数时,数据会有个回退现象,导致数据积压在一起

<template>
  <input type="text" v-model="keyWorld" />
  <h2>{{ keyWorld }}</h2>
</template>

<script>
import { customRef } from "vue";
export default {
  name: "App",
  setup() {
    // 自定义一个ref - 名为:myRef
    function myRef(value, delay) {
      return customRef((track, trigger) => {
        return {
          get() {
            console.log(`从myRef容器读取数据,将${value}赋值给他`);
            track(); // 通知Vue追踪Value的变化
            return value;
          },
          set(newValue) {
            console.log(`把myRef容器中数据修改为:${newValue}`);
            setTimeout(() => {
              value = newValue;
              trigger(); // 通知Value去重写解析模板
            }, delay);
          },
        };
      });
    }

    let keyWorld = myRef("Hello World", 500); // 自定义的ref
    return { keyWorld };
  },
};
</script>

防抖效果实现

<script>
import { customRef } from "vue";
export default {
  name: "App",
  setup() {
    let timer;
    // 自定义一个ref - 名为:myRef
    function myRef(value, delay) {
      return customRef((track, trigger) => {
        return {
          get() {
            console.log(`从myRef容器读取数据,将${value}赋值给他`);
            track(); // 通知Vue追踪Value的变化
            return value;
          },
          set(newValue) {
            console.log(`把myRef容器中数据修改为:${newValue}`);
            clearTimeout(timer);
            timer = setTimeout(() => {
              value = newValue;
              trigger(); // 通知Value去重写解析模板
            }, delay);
          },
        };
      });
    }

    let keyWorld = myRef("Hello World", 500); // 自定义的ref
    return { keyWorld };
  },
};
</script>

由图示可看出,只有在停止修改数据后,才会去重新解析模板

五、provide 与 inject

Vue3官方文档 - Provide / Inject

官方图示

作用:实现父组件与后代组件间通信

使用:父组件由一个 provide 选项来提供数据,后代组件有一个 inject 选项来开始使用这些数据(一般在父组件与深层子组件间使用)

具体写法:

// ###父组件中
setup(){
    .....
    let data = reactive({属性1:'...',属性2:'...'})
    provide('data',data)
    .....
}
// ###后代组件中
setup(){
    .....
    const data = inject('data') // inject()内填写provide('自定义命名',data)中自定义命名
    return(data)
    .....
}

案例练习

  • App.vue作为父组件,并设置一组数据,将其通过provide 传给深层子组件
  • 子组件:Child.vue
  • 深层子组件:DeepChild.vue

App.vue

<template>
  <div class="app">
    <h3>App组件 - 父组件, {{ name }} -- {{ date }}</h3>
    <Child></Child>
  </div>
</template>

<script>
import { provide, reactive, toRefs } from "vue";
import Child from "./components/Child.vue";
export default {
  name: "App",
  components: { Child },
  setup() {
    let game = reactive({
      name: "Splatoon3",
      date: "2022.7.29",
    });

    provide("game", game);
    return { ...toRefs(game) };
  },
};
</script>

<style>
.app {
  background-color: gray;
  padding: 10px;
}
</style>

Child.vue

<template>
  <div class="child">
    <h3>Child组件 - 子组件</h3>
    <DeepChild></DeepChild>
  </div>
</template>

<script>
import DeepChild from "./DeepChild.vue";
export default {
  name: "Child",
  components: { DeepChild },
};
</script>

<style>
.child {
  background-color: skyblue;
  padding: 10px;
}
</style>

DeepChild.vue

<template>
  <div class="DeepChild">
    <h3>deepChild组件 - 深层子组件, {{ game.name }} -- {{ game.date }}</h3>
  </div>
</template>

<script>
import { inject } from "vue";

export default {
  name: "DeepChild",
  setup() {
    const game = inject("game");
    return { game };
  },
};
</script>

<style>
.DeepChild {
  background-color: orange;
  padding: 10px;
}
</style>

六、响应式数据的判断

Vue3官方文档 - isRefisReactiveisReadonlyisProxy

  • isRef:检查一个值是否为ref对象
  • isReactive:检查一个值是否由 reactive 创建的响应式代理
  • isReadonly:检查一个对象是否由 readonly 创建的只读代理
  • isProxy:检查一个对象是否由 reactive 或者 readonly 方法创建的代理 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JHY97

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值