vue3(五)ref,reactive,toRef

136 阅读2分钟

ref

接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象仅有一个 .value property,指向该内部值。

<template>
  <div>
    <button @click="changeMsg">change</button>
    <div>{{ message }}</div>
  </div>
</template>
 
<script setup lang="ts">
import {ref} from 'vue'
let message: Ref<string | number> = ref("我是message")
const changeMsg = () => {
   message.value = "change msg"
}
</script>

isRef

判断是不是一个 ref 对象

import { ref, Ref, isRef } from 'vue'
let message: Ref<string | number> = ref("我是message")
let notRef:number = 123
const changeMsg = () => {
  message.value = "change msg"
  console.log(isRef(message)); //true
  console.log(isRef(notRef)); //false
}

shallowRef

创建一个跟踪自身 .value 变化的 ref,但不会使其值也变成响应式的
这样修改,不会触发响应式,页面不会改变

<template>
  <div>
    <button @click="changeMsg">change</button>
    <div>{{ message }}</div>
  </div>
</template>

<script setup lang="ts">
import { Ref, shallowRef } from 'vue'
type Obj = {
  name: string
}
let message: Ref<Obj> = shallowRef({
  name: "我是小刘"
})

const changeMsg = () => {
  message.value.name = '我不是小刘'
}
</script>

修改成这样就可以监听到

const changeMsg = () => {
  message.value = {
    name: "我不是小刘"
  }
}

triggerRef

强制更新页面DOM,上面的例子修改一下。使用 triggerRef() 强制更新

import { Ref, shallowRef, triggerRef } from 'vue'
type Obj = {
  name: string
}
let message: Ref<Obj> = shallowRef({
  name: "我是小刘"
})

const changeMsg = () => {
  message.value.name = '我不是小刘'
  // 强制更新dom
  triggerRef(message)
}

customRef

自定义ref,customRef 是个工厂函数要求我们返回一个对象 并且实现 get 和 set

<template>
  <div>
    {{ name }}
  </div>
  <hr>
  <button @click="change">修改 customRef</button>
</template>
 
<script setup lang='ts'>
import { customRef } from 'vue'

function myRef<T = any>(value: T) {
  return customRef((track, trigger) => {
    return {
      get() {
        track()
        return value
      },
      set(newVal) {
        console.log('触发了set')
        value = newVal
        trigger()
      }
    }
  })
}

const name = myRef<string>('我是小刘')

const change = () => {
  name.value = '我不是小刘'
}

</script>
<style scoped></style>

reactive

用来绑定引用数据类型 例如 对象 数组,不能绑定普通的数据类型,会报错
基本用法

import { reactive } from 'vue'
let person = reactive({
   name:"我是小刘"
})
// 修改
person.name = "我不是小刘"

数组异步赋值问题 这样赋值页面是不会变化的因为会脱离响应式

let person = reactive<number[]>([])
setTimeout(() => {
  person = [1, 2, 3]
  console.log(person);
  
},1000)

可以使用方法1、

import { reactive } from 'vue'
let person = reactive<number[]>([])
setTimeout(() => {
  const arr = [1, 2, 3]
  person.push(...arr)
  console.log(person);
  
},1000)

可以使用方法2、

import { reactive } from 'vue'
type Person = {
  list: number[]
}
let person = reactive<Person>({
  list: []
})
setTimeout(() => {
  person.list = [1, 2, 3]
  console.log(person);
}, 1000)

readonly

拷贝一份proxy对象将其设置为只读

import { reactive ,readonly} from 'vue'
const person = reactive({count:1})
const copy = readonly(person)
 //person.count++
//  error:无法为“count”赋值,因为它是只读属性。
 copy.count++

shallowReactive

只能对浅层的数据 如果是深层的数据只会改变值 不会改变视图

<template>
  <div>
    <div>{{ state }}</div>
    <button @click="change1">change1</button>
    <button @click="change2">change2</button>
  </div>
</template>

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

const obj = {
  a: 1,
  first: {
    b: 2,
    second: {
      c: 3
    }
  }
}

const state = shallowReactive(obj)

function change1() {
  // 页面变化
  state.a = 666
}
function change2() {
  // 页面没变化
  state.first.b = 888
  state.first.second.c = 9999
  console.log(state);
}

</script> 

toRef、toRefs、toRaw

toRef

只能修改响应式对象的值,对非响应式对象值,数据会改变但视图不会改变

<template>
  <div>
    obj:{{ obj }}
    <button @click="change">按钮</button>
    state:{{ state }}
  </div>
</template>

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

const obj = {foo: 1,bar: 1}

const state = toRef(obj, 'bar')

const change = () => {
  state.value++
  console.log(obj, state);
}
</script>

使用 reactive 把 obj 变成响应式对象,视图就会改变了

import { toRef, reactive } from 'vue'

const obj = reactive({ foo: 1, bar: 1 })

const state = toRef(obj, 'bar')

const change = () => {
  state.value++
  console.log(obj, state);
}

toRefs

批量创建ref对象,主要方便解构使用

import { reactive, toRefs } from 'vue'
const obj = reactive({
   foo: 1,
   bar: 1
})
 
let { foo, bar } = toRefs(obj)
 
foo.value++
console.log(foo, bar);

toRaw

将响应式对象转化为普通对象

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

const obj = reactive({
  foo: 1,
  bar: 1
})

// 响应式对象转化为普通对象
const state = toRaw(obj)

const change = () => {
  console.log(obj);
  console.log(state);
}
</script>