vue3 responsive objects: ref and reactive

ref()

<template>
  <button @click="changeMsg">Change message</button>
  <div>{<!-- -->{ msg }}</div>
  <div>{<!-- -->{ man }}</div>
</template>

<script lang="ts">
import { defineComponent,ref,Ref } from 'vue'

export default defineComponent({
  setup() {
    let msg: Ref<string> = ref("Hello")
      let man = ref({name:"wj"})
    const changeMsg = () => {
      msg.value = "I'm okay"
      console.log(msg);
      man.value.name = "hhhh"
      console.log(man);
      
    }

    return {
      msg,
      man,
      changeMsg
    }
  }
})
</script>

For simple objects

For complex objects, but the internal value is proxied by proxy

isRef()

Determine whether it is a ref object

<template>
  <button @click="handleClick">Click</button>
  <div>{<!-- -->{ msg1 }}</div>
  <div>{<!-- -->{ msg2 }}</div>
</template>

<script setup lang="ts">
import { ref,isRef } from 'vue'

let msg1 = ref("I am msg1")
let msg2 = "I am msg2"

const handleClick=()=>{
  console.log(isRef(msg1)); //true
  console.log(isRef(msg2)); //false
}
</script>

<style scoped></style>

shallowRef()

Shallow responsiveness. Create a ref that tracks changes to its own .value but does not make its value reactive as well

<template>
  <button @click="handleClick">Click</button>
  <div>{<!-- -->{ man }}</div>
</template>

<script setup lang="ts">
import { ref,shallowRef } from 'vue'

let man = shallowRef({
  name: "wj",
  code: {
    js:true
  }
})

const handleClick=()=>{
  man.value.code.js = false;
  console.log(man);
}
</script>

shallowRef is for complex objects. Its value is directly filled with values, not a proxy object, and cannot achieve deep response.

shallowRef cannot be used at the same time as ref. If used at the same time, shallowRef will also respond deeply.

<template>
  <button @click="handleClick">Click</button>
  <div>ref:{<!-- -->{ refMan }}</div>
  <div>shallowRef:{<!-- -->{ man }}</div>
</template>

<script setup lang="ts">
import { ref,shallowRef } from 'vue'

let man = shallowRef({
  name: "wj",
  code: {
    js:false
  }
})

let refMan = ref({
  name: "Xiaomi",
  code: {
    ts:false
  }
})

const handleClick = () => {
  refMan.value.code.ts = true
  man.value.code.js = true;
  console.log(refMan);
  console.log(man);
}
</script>

Summary:

  1. ref is a deep-level responsiveness, and shallowRef is a shallow-level responsiveness.
  2. Ref and shallowRef cannot be written together, otherwise it will affect shallowRef and cause the view to be updated.

tiggerRef()

Force update of page’s DOM

<template>
  <button @click="handleClick">Click</button>
  <div>shallowRef:{<!-- -->{ man }}</div>
</template>

<script setup lang="ts">
import { shallowRef, triggerRef } from 'vue'

let man = shallowRef("I am shallowRef")


const handleClick = () => {
  man.value = "I am shallowRef, I was changed";
  triggerRef(man)
  console.log(man);
}
</script>

customRef()

Official website introduction: https://cn.vuejs.org/api/reactivity-advanced.html#customref

Create a custom ref that explicitly declares control over dependency tracking and update triggering.

<template>
  <button @click="handleClick">Click</button>
  <div>customRef:{<!-- -->{ obj }}</div>
</template>

<script setup lang="ts">
import { customRef } from 'vue'

function myRef<T>(value:T) {
  return customRef((track, trigger)=> {
    return {
      get() {
        track()
        return value
      },
      set(newVal) {
        console.log("Triggered");
        
        value = newVal
        trigger()
      }
    }
  })
}
let obj = myRef<string>("I am customRef")

const handleClick = () => {
  obj.value = "I am I am customRef, I was changed";
  console.log(obj);
}
</script>

Usage scenarios: You can freely control responsive processing, such as when calling interfaces (official website example)

import { customRef } from 'vue'

export function useDebouncedRef(value, delay = 200) {
  let timeout
  return customRef((track, trigger) => {
    return {
      get() {
        track()
        return value
      },
      set(newValue) {
        clearTimeout(timeout)
        timeout = setTimeout(() => {
          value = newValue
          trigger()
        }, delay)
      }
    }
  })
}

reactive()

Official website: https://cn.vuejs.org/guide/essentials/reactivity-fundamentals.html#reactive

1. Reactive limits the value type and can only be used for object types (Object, Array, Collection (Map, Set))

<template>
  <button @click="change">Button</button>
  <hr/>
  <div>persion: {<!-- -->{ person }}</div>
</template>

<script setup lang="ts">
import { reactive } from 'vue'

let person = reactive({
  name: "Tom",
  age: 23,
  gender:1
})

const change = () => {
  person.name = "timi"
  console.log(person);
}

</script>

2. The entire object cannot be replaced: reactive is a proxy object and cannot be assigned directly, otherwise it will break its responsiveness.

<template>
  <button @click="noProxyChange">Modify directly</button>
  <hr/>
  <div>list: {<!-- -->{ list }}</div>
</template>

<script setup lang="ts">
import { reactive } from 'vue'

let list:string[] = reactive<string[]>([])

const noProxyChange = () => {
  let temp = ["1", "2", "3"]
  //Replaced the entire list object
  list =temp
  console.log(list);
}
</script>

Solution: Use the array’s own methods to change the array

<template>
  <button @click="proxyChange">Responsive modification</button>
  <hr/>
  <div>list: {<!-- -->{ list }}</div>
</template>

<script setup lang="ts">
import { reactive } from 'vue'

let list:string[] = reactive<string[]>([])

const proxyChange = () => {
  list.push("1")
  list.push("2")
  list.push("3")
  console.log(list);
}
</script>

<style scoped></style>

shallowReactive()

Shallow action form of reactive()

See the documentation for details: https://cn.vuejs.org/api/reactivity-advanced.html#shallowreactive

ref and reactive

  1. When ref binds the object type, we know from the source code that reactive is also called.
  2. .value is required for ref value acquisition and assignment, but not for reactive.