preface

It has been nearly half a year since the official release of Vue3. X. I believe that you have developed projects with Vue3. So, today we’ll take a look at the responsiveness apis in vue3.x.

Responsiveness API

reactive

Creates a reactive data.

Essence: Incoming data (complex types: arrays and JSON objects) is wrapped as a Proxy object. If you pass in other objects, the interface does not update automatically by default. If you want to update objects, you can do so by reassigning (creating a new object).

<template>
  <div class="reactive">
    <button @click="fn">Click on the</button>
    <p>{{ state }}</p>
    <button @click="fn1">Click on the 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>

Copy the code

ref

Creates a reactive data. Change the corresponding value must be followed by. Value.

Note: Do not add. Value inside the template tag.

<template>
  <div>
    <button @click="fn">Click on the</button>
    <p>{{state}}</p>
    <button @click="fn1">Click on the 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>
Copy the code

shallowReactive

What it does: Creates a reactive proxy that tracks the responsiveness of its own property, but does not perform deep reactive transformations of nested objects (exposing raw values).

Essence: Does not respond to nested objects, and the value tracks its first-level property.

<template>
  <div>
    <button @click="fn">Click on the</button>
    <button @click="fn1">Click on the 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"; / / responsiveness
    }
    function fn1(){
      state.age.number = 23; // Unresponsive
    }
    return {
      state,
      fn,
      fn1
    }
  }
}
</script>
Copy the code

shallowRef

What it does: Creates a ref that tracks its own.value changes but does not make its value responsive. Its value is not converted to a Proxy object.

<template>
  <div>
    <button @click="fn">Click on the</button>
    <p>{{ state }}</p>
    <button @click="fn1">Click on the 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"}, but the UI will not change.
      // triggerRef(state); // If you want to trigger the UI, you can use it.
    }
    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>
Copy the code

readonly

Gets an object (reactive or pure) or ref and returns the read-only proxy of the original proxy. Read-only proxies are deep: any nested property accessed is also read-only.

<template>
  <div>
    <button @click="fn">Click on the</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>
Copy the code

shallowReadonly

What it does: Creates a proxy that makes its own property read-only, but does not perform deep read-only conversions of nested objects (exposing raw values).

<template>
  <div>
    <button @click="fn">Click on the</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>
Copy the code

toRaw

Function: Convert a reactive object to a normal object.

Essence: Returns ordinary objects that have been transformed by reactive or Readonly methods into reactive proxies. This is a restore method that can be used for temporary reads without access being proxied/tracked and without triggering changes on writes. Holding a reference to the original object is not recommended.

<template>
  <div>
    <button @click="fn">Click on the</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>

Copy the code

markRaw

Purpose: Marks an object so that it will never be converted to proxy. Returns the object itself.

<template>
  <div>
    <button @click="fn">Click on the</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); // It prints name:123, but the UI does not change.
    }
    return{
      state,
      fn
    }
  }
}
</script>
Copy the code

toRef

If we use ref, we modify the reactive data without affecting the original data (copy). If toRef is used, we modify the reactive data without affecting the original data (citation).

Creates a new ref for a property on a source responsive object. You can then pass the REF out, preserving a reactive connection to its source property.

<template>
  <div>
    <button @click="fn">Click on the</button>
    <p>{{state}}</p>
    <button @click="fn1">Click on the 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); // The raw data does not change
      console.log(state);
    }
    // toRef
    function fn1(){
      state1.value = "345";
      console.log(os); // The raw data will change
      console.log(state1);
    }
    return {
      state,
      fn,
      state1,
      fn1
    }
  }
}
</script>
Copy the code

toRefs

What it does: Converts a reactive object to a normal object, where each property of the resulting object is a ref to the corresponding property of the original object.

Purpose: toRefs is useful when returning a reactive object from a synthesized function so that the consuming component can decompose/diffuse the returned object without losing its responsiveness.

<template>
  <div>
    <button @click="fn">Click on the</button>
    <p>{{state}}</p>
    <button @click="fn1">Click on the 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
  })
  // Convert to ref on return
  return toRefs(state)
}
</script>
Copy the code

customRef

What it does: Creates a custom REF with explicit control over its dependency trace and update trigger. It requires a factory function that takes track and trigger functions as arguments and should return an object with get and set.

<template>
  <div>
    <button @click="fn">Click on the</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>
Copy the code

computed

Function: When a dependency changes, the value assigned to it changes accordingly.

Note: It is not possible to modify computed directly.

<template>
  <div>
    <p>{{state}}</p>
    <p>{{os}}</p>
    <button @click="fn">Click on the</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; // The OS value will change accordingly
      // os.value = 26; // Write operation failed: computed value is readonly
    }
    return{
      state,
      os,
      fn
    }
  }
}
</script>
Copy the code

watchEffect

What it does: Runs a function immediately when its dependencies are tracked responsively, and rerunces it when the dependency changes.

<template>
  <div>
    <button @click="fn">Click on the</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;
    // It is executed on the first run and re-executed if the dependency changes in response.
    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>
Copy the code

watch

What it does: By default, it is also lazy — that is, the callback is invoked only when the listening source changes.

<template>
  <div>
    <button @click="fn">Click on the</button>
    <p>{{state}}</p>
    <button @click="fn1">Click on the 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>
Copy the code

conclusion

Thanks for reading, I hope I didn’t waste your time. There are many other uses for a responsive API that you can use in conjunction with code examples, but I’ve only covered them here. 2021 is coming, so act fast!

  • Welcome to follow my public numberThe front end of the road to disaster
  • Reply keywordse-books, you can get 12 front-end popular e-books.
  • Reply keywordsThe Little Red Book, 4th edition, you can get the latest JavaScript Advanced Programming (4th edition) ebook.
  • I have created a technical exchange and article sharing group, in which there are many front leaders of big factories. After following the public account, click the menu below to learn more and you can add my wechat. I look forward to your joining.