Vue3 - 响应性API

Souleigh ✨ 等级 615 0 0

前言

Vue3.x正式版发布已经快半年了,相信大家也多多少少也用Vue3.x开发过项目。那么,我们今天就整理下Vue3.x中的响应性API。

响应性API

reactive

作用: 创建一个响应式数据。

本质: 传入数据(复杂类型:数组和json对象)包装成一个Proxy对象。如果传入其他对象,默认情况下修改对象,界面不会自动更新,如果想更新,可以通过重新赋值(创建一个新的对象)的方式。

<template>  
  <div class="reactive">  
    <button @click="fn">点击</button>  
    <p>{{ state }}</p>  
    <button @click="fn1">点击1</button>  
    <p>{{ timeState }}</p>  
  </div>  
</template>  

<script>  
import { reactive } from "vue";  
export default {  
  name: "Reactive",  
  setup() {  
    let state = reactive({  
      name: "123",  
    });  
    function fn() {  
      console.log(state);  
      state.name = "456";  
    }  

    let timeState = reactive({  
      time: new Date(),  
    });  

    function fn1() {  
      const newTime = new Date(timeState.time.getTime());  
      newTime.setDate(timeState.time.getDate() + 1);  
      timeState.time = newTime;  
      console.log(timeState.time);  
    }  

    return {  
      state,  
      fn,  
      timeState,  
      fn1,  
    };  
  },  
};  
</script>  

ref

作用: 创建一个响应式数据。

本质: (该本质写的不够严谨)针对复杂类型还是reactive。当我们给ref函数传递一个值(一般是简单类型)之后,ref函数底层会自动将ref转换成reactive,即ref(123) => reactive({value:123}),所以修改对应的值必须在后面加上.value

注意点:template标签内不用加.value

<template>  
  <div>  
    <button @click="fn">点击</button>  
    <p>{{state}}</p>  
    <button @click="fn1">点击1</button>  
    <p>{{arrState}}</p>  
  </div>  
</template>  

<script>  
import {ref} from "vue";  
export default {  
  name:"Ref",  
  setup(){  
    let state = ref(123);  
    function fn () {  
      state.value = 345;  
    }  
    let arrState = ref([]);  
    function fn1 (){  
      arrState.value.push("1");  
    }  
    return {  
      state,  
      fn,  
      arrState,  
      fn1  
    }  
  }  
}  
</script>  

shallowReactive

作用: 创建一个响应式 proxy,跟踪其自身 property 的响应性,但不执行嵌套对象的深度响应式转换 (暴露原始值)。

本质: 对于嵌套对象不做响应,值跟踪自身的第一层property

<template>  
  <div>  
    <button @click="fn">点击</button>  
    <button @click="fn1">点击1</button>  
    <p>{{state}}</p>  
  </div>  
</template>  

<script>  
import { shallowReactive } from "vue"  
export default {  
  name:"ShallowReactive",  
  setup(){  
    let state = shallowReactive({  
      name:"maomin",  
      age:{  
        number:20  
      }  
    })  
    function fn(){  
      state.name = "123"; // 响应性  
    }  
    function fn1(){  
      state.age.number = 23; // 无响应性  
    }  
    return {  
      state,  
      fn,  
      fn1  
    }  
  }  
}  
</script>  

shallowRef

作用: 创建一个 ref,它跟踪自己的 .value 更改,但不会使其值成为响应式的。不会将其值转化为Proxy对象。

<template>  
  <div>  
    <button @click="fn">点击</button>  
    <p>{{ state }}</p>  
    <button @click="fn1">点击1</button>  
    <p>{{ state1 }}</p>  
  </div>  
</template>  

<script>  
import {   
  shallowRef,   
  ref,   
  // triggerRef   
} from "vue";  
export default {  
  name: "ShallowRef",  
  setup() {  
    let state = shallowRef({  
      name: "maomin",  
    });  
    let state1 = ref({});  
    function fn() {  
      state.value.name = "345";  
      console.log(state.value); // {name: "345"}, 但是UI界面不会变。  
      // triggerRef(state); // 如果想触发UI界面,可以使用它。  
    }  
    function fn1() {  
      state1.value = {  
        name: "123",  
      };  
      // eslint-disable-next-line no-irregular-whitespace  
      console.log(state1.value); // Proxy {name: "123"}  
    }  
    return {  
      state,  
      fn,  
      state1,  
      fn1,  
    };  
  },  
};  
</script>  

readonly

作用: 获取一个对象 (响应式或纯对象) 或 ref 并返回原始 proxy 的只读 proxy。只读 proxy 是深层的:访问的任何嵌套 property 也是只读的。

<template>  
  <div>  
    <button @click="fn">点击</button>  
    <p>{{os}}</p>  
    <p>{{state}}</p>  
  </div>  
</template>  

<script>  
import {reactive, readonly} from "vue";  
export default {  
  name:"Readonly",  
  setup(){  
    let state = reactive({  
      name:"maomin",  
      age:{  
        number:18  
      }  
    })  
    let os = readonly(state);  
    function fn(){  
      os.name = "123";  
    }  
    return{  
      os,  
      state,  
      fn  
    }  
  }  
}  
</script>  

shallowReadonly

作用: 创建一个 proxy,使其自身的 property 为只读,但不执行嵌套对象的深度只读转换 (暴露原始值)。

<template>  
  <div>  
    <button @click="fn">点击</button>  
    <p>{{os}}</p>  
    <p>{{state}}</p>  
  </div>  
</template>  

<script>  
import {  
  reactive,   
  shallowReadonly,  
  isReadonly  
  } from "vue";  
export default {  
  name:"ShallowReadonly",  
  setup(){  
    let state = reactive({  
      name:"maomin",  
      age:{  
        number:18  
      }  
    })  

    let os = shallowReadonly(state);  

    function fn(){  
       console.log(isReadonly(os.name)) //false  
       os.age.number = 20;  
    }  
    return{  
      state,  
      os,  
      fn,  
    }  
  }  
}  
</script>  

toRaw

作用: 响应式对象转普通对象。

本质: 返回由reactivereadonly 方法转换成响应式代理的普通对象。这是一个还原方法,可用于临时读取,访问不会被代理/跟踪,写入时也不会触发更改。不建议一直持有原始对象的引用。

<template>  
  <div>  
    <button @click="fn">点击</button>  
    <p>{{state}}</p>  
  </div>  
</template>  

<script>  
import { reactive, toRaw } from "vue";  
export default {  
  name:"ToRaw",  
  setup(){  
    const obj = {  
      name:"maomin"  
    };  
    let state = reactive(obj);  
    function fn(){  
      console.log(toRaw(state) === obj); //true  
      let obj1 = toRaw(state);  
      obj1.name = "123";  
      // eslint-disable-next-line no-irregular-whitespace  
      console.log(state); // Proxy {name: "123"}. 值虽改变,但是页面没有变化。  
    }  

    return {  
      state,  
      fn  
    }  
  }  
}  
</script>  

markRaw

作用: 标记一个对象,使其永远不会转换为 proxy。返回对象本身。

<template>  
  <div>  
    <button @click="fn">点击</button>  
    <p>{{state}}</p>  
  </div>  
</template>  

<script>  
import {markRaw,reactive} from "vue"  
export default {  
  name:"MarkRaw",  
  setup(){  
    let obj = {name:'maomin', age: 20};  
    obj = markRaw(obj);  
    let state = reactive(obj);  
    function fn(){  
      state.name = '123';  
      console.log(state); //这里虽然打印出name:123,但是UI界面不会改变。  
    }  
    return{  
      state,  
      fn  
    }  
  }  
}  
</script>  

toRef

如果使用ref,我们修改响应式的数据是不会影响到原始数据的(复制)。如果使用toRef,我们修改响应式的数据是会影响到原始数据的(引用)。

作用: 可以用来为源响应式对象上的 property 新创建一个 ref。然后可以将 ref 传递出去,从而保持对其源 property 的响应式连接。

<template>  
  <div>  
    <button @click="fn">点击</button>  
    <p>{{state}}</p>  
    <button @click="fn1">点击1</button>  
    <p>{{state1}}</p>  
  </div>  
</template>  

<script>  
import {reactive, ref, toRef} from "vue"  
export default {  
  name:"ToRef",  
  setup(){  
    let obj = {name:"maomin"};  
    let os = reactive(obj);  

    let state = ref(os.name);  
    let state1 = toRef(os,'name');  
    // ref  
    function fn(){  
      state.value = "123";  
      console.log(os); // 原始数据不会发生改变  
      console.log(state);  
    }  
    // toRef  
    function fn1(){  
      state1.value = "345";  
      console.log(os); // 原始数据会发生改变  
      console.log(state1);  
    }  
    return {  
      state,  
      fn,  
      state1,  
      fn1  
    }  
  }  
}  
</script>  

toRefs

作用: 将响应式对象转换为普通对象,其中结果对象的每个 property 都是指向原始对象相应 propertyref

用途: 当从合成函数返回响应式对象时,toRefs 非常有用,这样消费组件就可以在不丢失响应性的情况下对返回的对象进行分解/扩散。

<template>  
  <div>  
    <button @click="fn">点击</button>  
    <p>{{state}}</p>  
    <button @click="fn1">点击1</button>  
    <p>{{foo}}</p>  
  </div>  
</template>  

<script>  
import {reactive, toRefs} from "vue"  
export default {  
  name:"ToRefs",  
  setup(){  
    let obj = {  
      name:"maomin",  
      age:20  
    }  
    let os = reactive(obj);  
    let state = toRefs(os);  

    function fn(){  
      state.name.value = "123";  
      os.name = "234";  
      console.log(os);  
      console.log(state);  
      console.log(state.name.value === os.name); //true  
    }  

    const { foo, bar } = useFeatureX();  

    function fn1(){  
      foo.value = "2";  
    }  
    return {  
      fn,  
      state,  
      foo,  
      bar,  
      fn1  
    }  
  }  
}  


function useFeatureX() {  
  const state = reactive({  
    foo: 1  
  })  
  // 返回时转换为ref  
  return toRefs(state)  
}  
</script>  

customRef

作用: 创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。它需要一个工厂函数,该函数接收 tracktrigger 函数作为参数,并应返回一个带有 getset 的对象。

<template>  
  <div>  
    <button @click="fn">点击</button>  
    <p>{{state}}</p>  
  </div>  
</template>  

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

function myRef(value){  
  return customRef((track, trigger)=>{  
    return {  
      get(){  
        track();  
        console.log('get',value);  
        return value;  
      },  
      set(newValue){  
        console.log('set',newValue);  
        value = newValue;  
        trigger();  
      }  
    }  
  })  
}  
export default {  
  name:"CustomRef",  
  setup(){  
    let state = myRef(18);  

    function fn(){  
      state.value = 19;  
    }  
    return {  
      state,  
      fn  
    }  
  }  
}  
</script>  

computed

作用: 依赖项变化时,其赋予的值也就相应改变。

注意点: 直接修改computed是不可以的。

<template>  
  <div>  
    <p>{{state}}</p>  
    <p>{{os}}</p>  
    <button @click="fn">点击</button>  
  </div>  
</template>  

<script>  
import {computed,ref} from "vue"  
export default {  
  name: "Computed",  
  setup(){  
    let state = ref(12);  
    let os = computed(() => state.value + 1);  

    function fn(){  
      state.value = 23; // os的值也会相应改变  
      // os.value = 26; // Write operation failed: computed value is readonly  
    }  
    return{  
      state,  
      os,  
      fn  
    }  
  }  
}  
</script>  

watchEffect

作用: 在响应式地跟踪其依赖项时立即运行一个函数,并在更改依赖项时重新运行它。

<template>  
  <div>  
    <button @click="fn">点击</button>  
    <p>{{state}}</p>  
    <p>{{state1}}</p>  
    <p>{{num}}</p>  
  </div>  
</template>  

<script>  
import { reactive, ref, watchEffect } from "vue"  
export default {  
  name:"WatchEffect",  
  setup(){  
    let state = ref(0);  
    let state1 = reactive({  
      name:"maomin"  
    })  
    let num = 1;  
    // 首次运行时会执行它,如果响应依赖项改变时,会重新执行它。  
    watchEffect(()=>{  
      // console.log(num);  
      console.log(state.value);  
      console.log(state1);  
    })  

    function fn() {  
      state.value = 3;  
      state1.name = "123";  
      num = 2;  
    }  

    return{  
      fn,  
      state,  
      state1,  
      num  
    }  
  }  
}  
</script>  

watch

作用: 默认情况下,它也是惰性的——即回调仅在侦听源发生更改时调用。

<template>  
  <div>  
    <button @click="fn">点击</button>  
    <p>{{state}}</p>  
    <button @click="fn1">点击1</button>  
    <p>{{state1}}</p>  
  </div>  
</template>  

<script>  
import {reactive, ref, watch} from "vue"  
export default {  
  name:"Watch",  
  setup(){  

    // reactive  
    let state = reactive({  
      name:"maomin"  
    })  

    watch(  
      () => state.name,  
      (count) =>{  
        console.log(count); //123  
      }  
    )  

    function fn() {  
      state.name = "123";  
    }  

    //ref  
    let state1 = ref(1);  
    watch(  
      state1,  
      (count) =>{  
        console.log(count); //2  
      }  
    )  

    function fn1() {  
      state1.value = 2;  
    }  

    return {  
      state,  
      fn,  
      fn1,  
      state1  
    }  
  }  
}  
</script>  

结语

谢谢阅读,希望没有浪费您的时间。可以结合代码例子自己敲敲代码,响应性API还有很多用处,这里只介绍了九牛一毛,赶快行动起来吧!

收藏
评论区

相关推荐

Vue3 的 15 个常用 API
来自公众号:前端印象 本文会频繁地对比Vue2来介绍Vue3,也将对各个API结合代码实例讲解,这既是对自己知识的总结,也希望能帮助到大家 一、前言 大家都知道,现在Vue3的各个版本已经陆续发布了,并且有很多的团队已经着手各个库的开发与Vue2向Vue3的升级,我们当然也不能落后,所以赶紧将你手中的Vue2升级到Vue3,跟着本文一起学
Vue3.0 高频出现的几道面试题
1. Vue 3.0 性能提升主要是通过哪几方面体现的? 1.响应式系统提升 vue2在初始化的时候,对data中的每个属性使用definepropery调用getter和setter使之变为响应式对象。如果属性值为对象,还会递归调用defineproperty使之变为响应式对象。 vue3使用proxy对象重写响应式。proxy的性能本来比def
Vue3.0 所采用的 Composition Api 与 Vue2.x 使用的 Options Api 有什么不同?
开始之前 Composition API 可以说是Vue3最大的特点,那么为什么要推出Composition Api,解决了什么问题? 通常使用Vue2开发
Vue UI组件库对比与选择
主流组件库对比PC端| UI组件库名 | github star | 是否可自定义主题 | 是否支持vue3 | 发布时间 | 稳定性 | 贡献者 || | | | | | | || | | 可自定义 | 支持,beta版本,, | 201608,4年半 | 长期支持,最新两个
Kubernetes Ingress — Kong
Kong 是由 Mashape 公司开源的一个高性能、高可用、易扩展的 API Gateway 项目,基于OpenResty(Nginx Lua模块),并提供了插件实现 API 的 AOP 功能。可以通过负载均衡、插件扩展等方式,来处理网络请求。 Kong 主要的概念Servi
Hook API 索引 – React
Hook API 索引_Hook_ 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。本页面主要描述 React 中内置的 Hook API。如果你刚开始接触 Hook,那么可能需要先查阅 。你也可以在 章节中获取有用的信息。 基础 Hook
浅谈Vue3新特性
Vue3的已发布一段时间了,新的Vue3在语法以及底层都进行了全新的重构,带来了更快的运行速度,更小的构建包,更友好的编程规范,让我们来看看有哪些变化吧。更快传统的虚拟dom算法:组件patch的时候,需要重新创建整个vdom树,然后遍历整棵树进行diff,update...更快的虚拟dom算法,源自编译模板时给予更多的运行时提示:1. 编译模板时对动
vue3 - 组件通信
vue3 组件通信 和vue2的通信方式基本一致,只是存在写法上的差异 props/emit setup函数接收两个参数,props和context(上下文,其中有一个 emit) 用法展示 // 父组件 <template <ibutton :type'type' @onClick
Vue3.0 高频出现的几道面试题
1、Vue 3.0 性能提升主要是通过哪几方面体现的? 1.响应式系统提升vue2在初始化的时候,对data中的每个属性使用definepropery调用getter和setter使之变为响应式对象。如果属性值为对象,还会递归调用defineproperty使之变为响应式对象。vue3使用proxy对象重写响应式。proxy的性能本来比defineprope
「快速学习系列」我熬夜整理了Vue3.x响应性API
前言Vue3.x正式版发布已经快半年了,相信大家也多多少少也用Vue3.x开发过项目。那么,我们今天就整理下Vue3.x中的响应性API。响应性API reactive作用: 创建一个响应式数据。本质: 传入数据(复杂类型:数组和json对象)包装成一个Proxy对象。如果传入其他对象,默认情况下修改对象,界面不会自动更新,如果想更新,可以通过重新赋值(创建
「快速学习系列」我熬夜整理了Vue3.x响应性API
前言Vue3.x正式版发布已经快半年了,相信大家也多多少少也用Vue3.x开发过项目。那么,我们今天就整理下Vue3.x中的响应性API。响应性API reactive作用: 创建一个响应式数据。本质: 传入数据(复杂类型:数组和json对象)包装成一个Proxy对象。如果传入其他对象,默认情况下修改对象,界面不会自动更新,如果想更新,可以通过重新赋值(创建
微信小程序体验composition-api(类似vue3)
微信小程序compositionapi用该是什么样子? 使用使用起来应该像是这个样子wxue(options) setup配置应该是包含一个setup选项是一个函数,返回的函数可以this.xxx调用,返回的数据可以this.data.xxx用到,如下import wxue, reactive from 'wxue'wxue( setup(option
Vue3 - 响应性API
前言Vue3.x正式版发布已经快半年了,相信大家也多多少少也用Vue3.x开发过项目。那么,我们今天就整理下Vue3.x中的响应性API。响应性API reactive作用: 创建一个响应式数据。本质: 传入数据(复杂类型:数组和json对象)包装成一个Proxy对象。如果传入其他对象,默认情况下修改对象,界面不会自动更新,如果想更新,可以通过重新赋值(创建
你可能会用到的JS工具函数(第二期)
Vue3在script标签中引入 const oDiv document.createElement('div'); const oScript document.createElement('script'); oDiv.setAttribute('id', 'app'); oScript.type 'text/java
Vue3 + TypeScript 开发实践总结
前言迟来的Vue3文章,其实早在今年3月份时就把Vue3过了一遍。<br/在去年年末又把 TypeScript 重新学了一遍,为了上 Vue3 的车,更好的开车。<br/在上家公司4月份时,上级领导分配了一个内部的 党务系统开发 ,这个系统前端是由我一个人来开发,功能和需求也不怎么复杂的一个B 端 系统,直接上的 Vue3 + TypeScript + El