「快速学习系列」我熬夜整理了Vue3.x响应性API

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

前言


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


作用: 创建一个响应式数据。修改对应的值必须在后面加上.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还有很多用处,这里只介绍了九牛一毛。2021年到来,赶快行动起来吧!



相关文章
|
27天前
|
Web App开发 缓存 小程序
【Azure API 管理】从微信小程序访问APIM出现200空响应的问题中发现CORS的属性[terminate-unmatched-request]功能
【Azure API 管理】从微信小程序访问APIM出现200空响应的问题中发现CORS的属性[terminate-unmatched-request]功能
|
1月前
|
JSON 前端开发 API
[flask]统一API响应格式
[flask]统一API响应格式
|
26天前
|
存储 JSON 机器人
【Azure 机器人】微软Azure Bot 编辑器系列(2) : 机器人/用户提问回答模式,机器人从API获取响应并组织答案 (The Bot Framework Composer tutorials)
【Azure 机器人】微软Azure Bot 编辑器系列(2) : 机器人/用户提问回答模式,机器人从API获取响应并组织答案 (The Bot Framework Composer tutorials)
|
3月前
|
JSON 监控 中间件
中间件在API请求/响应处理
【6月更文挑战第16天】
38 7
|
3月前
|
JavaScript 中间件 API
中间件api响应处理
【6月更文挑战第14天】
39 5
|
3月前
|
前端开发 中间件 API
中间件API 请求和响应
【6月更文挑战第13天】
34 3
|
2月前
|
API
前后端数据交互,API风格组合式API和选项式API,setup是一个标识,组合式编写的意思,使定义count.value的值自增的写法,组合式API使用axios的写法,ref定义响应数据写法
前后端数据交互,API风格组合式API和选项式API,setup是一个标识,组合式编写的意思,使定义count.value的值自增的写法,组合式API使用axios的写法,ref定义响应数据写法
|
2月前
|
存储 API Go
学习gin-vue-admin之创建api和swagger
学习gin-vue-admin之创建api和swagger
|
2月前
|
JavaScript 前端开发 Java
|
4月前
|
存储 Java API
【JAVA学习之路 | 提高篇】[内部类与常见API]String类
【JAVA学习之路 | 提高篇】[内部类与常见API]String类