[web教学] 从Vue2到Vue3【四】——Composition API(第四章)

[复制链接]
查看872 | 回复0 | 2023-8-23 11:59:59 | 显示全部楼层 |阅读模式 来自 中国北京
系列文章目次

内容链接从Vue2到Vue3【零】Vue3简介从Vue2到Vue3【一】Composition API(第一章)从Vue2到Vue3【二】Composition API(第二章)从Vue2到Vue3【三】Composition API(第三章)从Vue2到Vue3【四】Composition API(第四章)从Vue2到Vue3【五】从Vue2到Vue3【五】——新的组件(Fragment、Teleport、Suspense)从Vue2到Vue3【六】从Vue2到Vue3【六】——Vue3的改变(文末送书)

  

媒介

随着Vue 3的发布,我们迎来了一套强大且令人兴奋的组合式API,这为开发者带来了更多机动性和可维护性。Vue 3的组合式API不但改变了我们编写Vue组件的方式,还引入了一些新的组件和一些小的但实用的改变。在这篇文章中,我们将深入探究Vue 3组合式API中的customRef、provide和inject以及相应式数据的判定,让我们一起开始这个令人兴奋的学习之旅吧!
一、customRef



  • customRef:

    • 创建一个自界说的 ref,并对其依赖项跟踪和更新触发进行显式控制。
    • customRef适用于须要自界说读取和写入逻辑的场景。
    • 提供了更多机动性,可以根据详细需求定制读取和写入的运动
    • 可以与相应式体系无缝集成,保持一致的Vue开发体验。

   ref实在和customRef很相似,都可以创建相应式数据,下面说说他们的异同点
  

  • 类似点:

  • 相应式: 无论是customRef照旧ref都可以大概创建相应式的数据
  • 访问值: 无论是customRef照旧ref都可以大概通过.value属性来访问内部的值。(操纵值时都须要加.value)


  • 区别:

  • 创建方式: customRef须要传入一个函数,并在函数中界说自界说的读取和写入逻辑;而ref只须要传入初始值即可。
  • 读取和写入逻辑: customRef允许你界说自己的读取和写入逻辑,可以实现更机动的相应式运动;而ref会直接访问内部的值。
  • 依赖追踪: customRef允许你在读取和写入逻辑中手动追踪依赖,通过track和trigger函数来实现;而ref会主动追踪读取和写入的依赖。
  1. <template>
  2.         <input type="text" v-model="keyword">
  3.         <h3>{{keyword}}</h3>
  4. </template>
  5. <script>
  6.         import {customRef} from 'vue'
  7.         export default {
  8.                 name:'Demo',
  9.                 setup(){
  10.                         //自定义一个myRef
  11.                         function myRef(value,delay){
  12.                                 let timer
  13.                                 //通过customRef去实现自定义
  14.                                 return customRef((track,trigger)=>{
  15.                                         return{
  16.                                                 get(){
  17.                                                         track() //告诉Vue这个value值是需要被“追踪”的
  18.                                                         return value
  19.                                                 },
  20.                                                 set(newValue){
  21.                                                         clearTimeout(timer) // 当再次输入时清空上次的定时器 重新开启一个新的定时器
  22.                                                         timer = setTimeout(()=>{
  23.                                                                 value = newValue  // 直到在delay这段时间不再输入时 才会更新模板上的值
  24.                                                                 trigger() 通知Vue去重新解析模板
  25.                                                         },delay)
  26.                                                 }
  27.                                         }
  28.                                 })
  29.                         }
  30.                         let keyword = myRef('hello',500) //使用程序员自定义的ref
  31.                         return {
  32.                                 keyword
  33.                         }
  34.                 }
  35.         }
  36. </script>
复制代码
这个官方给出的案例:当用户在input输入时,下方的h3标签延迟更新( 本质上就是一个防抖)
防抖指的是在肯定时间内如果再次触发该变乱,那么将重新计时,直到该时间内没有再次触发,才会实行变乱;而节流则是在肯定时间内只能触发一次变乱。在实现方面可以使用定时器或时间戳等技术来实现。其中,防抖适用于像搜索框这样须要输入完整关键字才会产生终极效果的场景;而节流则更恰当于须要频繁触发但每次实行变乱耗时较久的场景。

   myref是自界说的一个函数,所以须要有返回值,返回的值是使用customRef自界说的相应式数据
customRef内部有getter和setter,当解析模版时须要读取值(getter),当在input输入时须要重新设置值(setter)
  初始读取值时

修改值时

总结来说,customRef和ref都是Vue 3提供的用于创建相应式数据的函数,它们的告急区别在于创建方式读取和写入逻辑依赖追踪。你可以根据自己的须要选择使用哪种函数来创建相应式数据。
customRef真实场景使用要团结组件库的处理是否支持,不能很好的应用到组件库里,由于组件库里都有自己的数据劫持
(相应式实现原理数据劫持这块,在讲完vue3的根本使用后,会出一篇文章详细解说,接待订阅本系列,恒久更新!)
二、provide 与 inject



  • provide 与 inject

    • provide和inject是一对用于实现父组件向子孙组件通报数据的特殊组合。它们可以资助我们在组件树中跨层级地共享数据,而无需通过逐层通报props的方式。
    • provide 函数吸收两个参数:provide( name,value ),

      • name:界说 提供给子孙们数据的 name 。
      • value :提供数据的值。

    • inject(name,default)

      • name:吸收 provide 提供的属性名。
      • default:设置默认值,是可选参数。
        (当父亲没有provide值时,子组件注入使用的就是默认值,默认值也没有的话就是undefined)


父组件用一个 provide 选项来提供数据,后代组件用一个 inject 来吸收并使用这些数据
父组件代码
  1. <template>
  2.   <div class="app">
  3.     <h3>我是App组件(祖),{{ name }}--{{ price }}</h3>
  4.     <Child />
  5.   </div>
  6. </template>
  7. <script>
  8. import { reactive, toRefs, provide } from "vue";
  9. import Child from "./components/Child.vue";
  10. export default {
  11.   name: "App",
  12.   components: { Child },
  13.   setup() {
  14.     let car = reactive({ name: "奔驰", price: "40W" });
  15.     provide("car", car); //给自己的后代组件传递数据
  16.     setTimeout(() => {
  17.       // 过一秒钟修改父亲的car 看下子组件数据是否改变 若改变 则说明传递给子孙组件的数据也是响应式的
  18.       car.name = '宝马'
  19.     }, 1000);
  20.     return { ...toRefs(car) };
  21.   },
  22. };
  23. </script>
  24. <style>
  25. .app {
  26.   background-color: gray;
  27.   padding: 10px;
  28. }
  29. </style>
复制代码
子组件代码
  1. <template>
  2.         <div class="child">
  3.                 <h3>我是Child组件(子),{{ name }}--{{ price }}</h3>
  4.                 <Son/>
  5.         </div>
  6. </template>
  7. <script>
  8.         import {inject, toRefs} from 'vue'
  9.         import Son from './Son.vue'
  10.         export default {
  11.                 name:'chIld',
  12.                 components:{Son},
  13.                 setup(){
  14.                         let car = inject('car')
  15.                         return {
  16.                                 ...toRefs(car)
  17.                         }
  18.                 }
  19.         }
  20. </script>
  21. <style>
  22.         .child{
  23.                 background-color: skyblue;
  24.                 padding: 10px;
  25.         }
  26. </style>
复制代码
孙组件代码
  1. <template>
  2.         <div class="son">
  3.                 <h3>我是Son组件(孙),{{car.name}}--{{car.price}}</h3>
  4.         </div>
  5. </template>
  6. <script>
  7.         import {inject} from 'vue'
  8.         export default {
  9.                 name:'sOn',
  10.                 setup(){
  11.                         let car = inject('car')
  12.                         return {car}
  13.                 }
  14.         }
  15. </script>
  16. <style>
  17.         .son{
  18.                 background-color: orange;
  19.                 padding: 10px;
  20.         }
  21. </style>
复制代码
效果 (父组件给子孙组件通报相应式数据,父亲修改值后,子孙组件数据也会变革)

Vue框架采用的是单向数据流的数据管理模式 ===> 子孙组件不允许修改从父组件通报下来的值,这样会造成数据流向不清晰加粗样式


  • 这种数据流的计划有以下几个长处:

    • 数据的运动清晰可控:数据从父组件通报到子组件,形成了明确的数据运动路径,使得数据的变革可以追溯和控制。
    • 组件的独立性:子组件只须要关心自己的数据和逻辑,不须要关心父组件的详细实现细节,提高了组件的独立性和可复用性。
    • 数据的可预测性:由于数据只能从父组件流向子组件,数据的变革只能通过父组件来触发,镌汰了数据的复杂性和不可预测性。

所以这里固然是使用 provide 和 inject 在父组件和子孙组件之间通报数据,依然不能在后代组件中修改数据,为了避免这个题目,父组件在通报值时,应当使用readonly来限制子孙组件修改数据
升级版父组件传值
  1.     provide("car", readonly(car)); //给自己的后代组件传递只读数据
复制代码
子组件内修改值的后果 : 报错,而且值不能被修改,nice!
  1.                         setTimeout(() => {
  2.                                 car.name = '五菱宏光'
  3.                         }, 2000);
复制代码

三、相应式数据的判定



  • isRef: 查抄一个值是否为一个ref对象
  • isReactive: 查抄一个对象是否是由 reactive 创建的相应式署理
  • isReadonly: 查抄一个对象是否是由 readonly 创建的只读署理
  • isProxy: 查抄一个对象是否是由 reactive 或者 readonly 方法创建的署理
  1. <template>
  2.         <h3>我是App组件</h3>
  3. </template>
  4. <script>
  5.         import {ref, reactive,toRefs,readonly,isRef,isReactive,isReadonly,isProxy } from 'vue'
  6.         export default {
  7.                 name:'App',
  8.                 setup(){
  9.                         let car = reactive({name:'奔驰',price:'40W'})
  10.                         let sum = ref(0)
  11.                         let car2 = readonly(car)
  12.                         console.log(isRef(sum)) //true
  13.                         console.log(isReactive(car)) //true
  14.                         console.log(isReadonly(car2)) //true
  15.                         console.log(isProxy(car)) //true
  16.                         console.log(isProxy(sum)) //false
  17.                        
  18.                         return {...toRefs(car)}
  19.                 }
  20.         }
  21. </script>
  22. <style>
  23.         .app{
  24.                 background-color: gray;
  25.                 padding: 10px;
  26.         }
  27. </style>
复制代码

四、Composition API 与 Options API



  • Options API
    在Options API中,组件的各种选项(data、methods、computed、watch)是通过一个个独立的配置项来进行界说和构造的。这样的计划可能会导致代码的分散,特殊是在大型组件中,很难追踪和管理各个选项之间的关联。

  • Composition API
    在组合式API中,各种功能选项可以根据其逻辑关联性进行组合

在组合式API中,可以使用setup()函数来构造和界说组件的逻辑。setup()函数中可以使用各种功能函数(如reactive、ref、computed等)来声明相应式数据、盘算属性、变乱处理函数等,而不须要将它们分散在差异的选项中。这样可以使得逻辑代码更加会合和易于维护。
别的,由于组合式API将数据和逻辑进行组合,使得组件的代码更加模块化和可复用(hooks)。差异的逻辑可以通过将差异的功能函数组合在一起来构建差异的组件,提高了代码的可维护性和可读性。
总结来说,在图中可以看到,使用组合式API可以将干系逻辑组合在一起,简化了代码布局,并提供了更好的可读性和可维护性。相比于Options API,组合式API更加机动和强大,尤其适用于复杂的组件和大型项目。
总结

本系列到这,解说完了组合式API,接下来将为各人带来新的组件小的改变

来源:https://blog.csdn.net/m0_57524265/article/details/131863726
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则