热搜:前端 nest neovim nvim

Vue3: reactive, ref,toRef,toRefs用法和区别

lxf2023-05-28 01:42:23

Vue3的CompositionAPI 创建响应式对象的方式:

  • reactive
  • ref
  • toRef
  • toRefs

reactive

reactive 方法 根据传入的对象 ,创建返回一个深度响应式对象响应式对象看起来和传入的对象一样,但是,响应式对象属性值改动,不管层级有多深,都会触发响应式。新增和删除属性也会触发响应式。

看一个例子,通过reactive创建了一个响应式,然后3秒之后,做以下三种方式操作,都会触发响应式

  • 改变 name属性
  • 深度改变 address属性
  • 新增 school属性
  • 删除 age属性
<template>
  <div class="demo">
    <div>姓名:{{state.name}}</div>
    <div v-if="state.age>0">年龄:{{state.age}}</div>
    <div>地址:{{state.address.provoince}} - {{state.address.city}} - {{state.address.street}}</div>
  </div>

  <div class="demo">
    <div>学校:{{state.school||'自学成才'}}</div>

  </div>
</template>

<script>
import { reactive } from 'vue'
export default {
  name: 'reactivedemo',
  setup () {
    // 响应式对象
    const state = reactive({
      name: '太凉',
      age: 18,
      hobby: ['游泳', '爬山'],
      address: {
        provoince: '北京',
        city: '北京',
        street: '东城区长安街'
      }
    })

    // 过3秒后改变
    setTimeout(() => {
      // update1:改变name属性
      state.name = '冰箱太凉'

      // update2:深度改变 address属性
      state.address.provoince = '山东省' // 年龄改为30
      state.address.city = '临沂市'

      // update3:新增 school属性
      state.school = '清华北大'

      // update4:删除 年龄属性
      delete state.age

      // update5:数组 添加一项
      state.hobby.push('打豆豆')
    }, 3000)

    return {
     //注意这里不能通过 ...state 方式结构,这样会丢失响应式
      state  
    }
  }
}
</script>

<style scoped>
.demo {
  text-align: left;
  width: 600px;
  margin: 20px auto;
}
</style>

效果

Vue3: reactive, ref,toRef,toRefs用法和区别

重点:

  • reactive 只能 给对象添加响应式,对于值类型,比如StringNumberBooleanSymbol无能为力。

  • 不能通过 ...state 方式结构,这样会丢失响应式。下面这种方式是错误的

    //注意这里不能通过 ...state 方式结构,这样会丢失响应式。
     return {
         ...state  
     }
    

ref

上面我们提到 reactive 只能给对象,数组 添加响应式,如果想给值类型(StringNumberBooleanSymbol)添加响应式,就要用到ref,所以ref作用如下:

  • 生成值类型响应式数据
  • 通过.vue值修改
  • 生成对象和数组类型的响应式对象**(对象和数组一般会选用reactive方式,比较便捷)**
<template>
  <div>
    <div>countRef:{{countRef}}</div>
    <div>objCountRef:{{objCountRef.count}}</div>
    <div>爱好:{{hobbyRef.join('---')}}</div>
  </div>
</template>

<script>
import { ref } from 'vue'
export default {
  name: 'refdemo',
  setup () {
    // 值类型
    const countRef = ref(1)
    console.log(countRef)

    // 对象
    const objCountRef = ref({ count: 1 })

    // 数组
    const hobbyRef = ref(['爬山', '游泳'])

    setTimeout(() => {
      // 通过value改变值
      countRef.value = 2
      objCountRef.value.count = 3
      hobbyRef.value.push('吃饭')
    }, 4000)

    return {
      countRef,
      objCountRef,
      hobbyRef
    }
  }
}
</script>

效果:

Vue3: reactive, ref,toRef,toRefs用法和区别

toRef

  • 针对一个响应式对象(reactive 封装)的 prop(属性)创建一个ref,且保持响应式
  • 两者 保持引用关系

我们直接看一个例子,然后理解一下上面两句话

<template>
  <div class="demo">
    <div>姓名--state.name:{{state.name}}</div>
    <div>姓名2--nameRef:{{nameRef}}</div>
    <div>年龄:{{state.age}}</div>
  </div>
</template>

<script>
import { reactive, toRef } from 'vue'
export default {
  name: 'reactivedemo',
  setup () {
    // 响应式对象
    const state = reactive({
      name: '太凉',
      age: 18
    })

    // 通过toRef创建一个Ref响应式
    const nameRef = toRef(state, 'name')

    // 过3秒后改变 两者 保持引用关系 
    setTimeout(() => {
      // update1:改变name属性
      state.name = '冰箱太凉'
    }, 3000)

    // 过6秒后改变 两者 保持引用关系 
    setTimeout(() => {
      // update1:改变name属性
      nameRef.value = '我就是冰箱太凉'
    }, 6000)

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

效果图:

Vue3: reactive, ref,toRef,toRefs用法和区别

toRefs

toRefs 是一种用于破坏响应式对象并将其所有属性转换为 ref 的实用方法

  • 将响应式对象(reactive封装)转成普通对象
  • 对象的每个属性(Prop)都是对应的ref
  • 两者保持引用关系

直接看demo:

<template>
  <div class="demo">
    <h3>state 方式 不推荐的方式绑定</h3>
    <div>姓名--state.name:{{state.name}}</div>
    <div>年龄--state.age:{{state.age}}</div>
  </div>
  <div class="demo">
    <h3>toRefs之后的 方式 推荐这种方式,return需要{...toRefs(state)}</h3>
    <div>姓名--name:{{name}}</div>
    <div>年龄--age:{{age}}</div>
  </div>
</template>
<script>
import { reactive, toRefs } from 'vue'
export default {
  name: 'reactivedemo',
  setup () {
    // 响应式对象
    const state = reactive({
      name: '太凉',
      age: 18
    })

    // 通过toRefs创建一个响应式对象属性的Ref
    const toRefsValue = toRefs(state)

    // 过3秒后改变  两者保持引用关系
    setTimeout(() => {
      state.name = '冰箱太凉'
      state.age = '30'
    }, 3000)

    // 过6秒后改变 两者保持引用关系
    setTimeout(() => {
      toRefsValue.name.value = '我就是宇宙小超人'
      toRefsValue.age.value = '101'
    }, 6000)

    return {
      // 不建议使用这种方式,可以用下面的方式直接替换
      state,
      // 最佳方式:这里是结构 将 name的ref,age的ref结构到对象根下面
      ...toRefsValue
    }
  }
}
</script>

效果:

Vue3: reactive, ref,toRef,toRefs用法和区别

最佳实践

如何选择 refreactive?建议:

  1. 基础类型值(StringNumberBooleanSymbol) 或单值对象(类似{ count: 1 }这样只有一个属性值的对象) 使用 ref
  2. 引用类型值(ObjectArray)使用 reactive

使用toRefs(state)方式返回

<template>
  <div>
    <div>姓名:{{name}}</div>
    <div>年龄:{{age}}</div>
  </div>
</template>

<script>
import { reactive, toRefs } from 'vue'
export default {
  setup () {
    const state = reactive({
      age: 20,
      name: '太凉'

    })

    const stateAsRefs = toRefs(state)
    return {
      ...stateAsRefs
    }
  }
}
</script>

注意reactive封装的响应式对象,不要通过解构的方式return,这是不具有响应式的。可以通过 toRefs 处理,然后再解构返回,这样才具有响应式

const state = reactive({...});
return {...state}; // 这种方式将丢失响应式,是一种错误的方式
return toRefs(state); // works

最后

水平有限,如有错误,欢迎留言指正

本网站是一个以CSS、JavaScript、Vue、HTML为核心的前端开发技术网站。我们致力于为广大前端开发者提供专业、全面、实用的前端开发知识和技术支持。 在本网站中,您可以学习到最新的前端开发技术,了解前端开发的最新趋势和最佳实践。我们提供丰富的教程和案例,让您可以快速掌握前端开发的核心技术和流程。 本网站还提供一系列实用的工具和插件,帮助您更加高效地进行前端开发工作。我们提供的工具和插件都经过精心设计和优化,可以帮助您节省时间和精力,提升开发效率。 除此之外,本网站还拥有一个活跃的社区,您可以在社区中与其他前端开发者交流技术、分享经验、解决问题。我们相信,社区的力量可以帮助您更好地成长和进步。 在本网站中,您可以找到您需要的一切前端开发资源,让您成为一名更加优秀的前端开发者。欢迎您加入我们的大家庭,一起探索前端开发的无限可能!