Vue3中的响应式 api 总结

122 阅读4分钟

Vue3中的响应式 api

setup入口函数

作用

  • setup 函数是一个新的新的组件选项,作为组件中组合式 api 的起点(入口函数)
  • setup 函数只会在组件初始化的时候执行一次
  • setup 函数在 beforCreate 生命周期钩子执行之前执行,这时实例还没有生成,this不可用

代码演示

export default{
  setup(){
    console.log('setup执行了');
    console.log(this);
  },
  beforeCreate () {
    console.log('beforeCreate执行了');
    console.log(this);
  }
}

运行截图

1.jpg

reactive

作用

reactive 是一个可执行函数,接收一个普通的对象传入,把 对象数据 转化为响应式对象并返回

使用步骤

  • vue 框架中导入 reactive 函数
import { reactive } from 'vue'
  • setup 函数中调用 reactive 函数并将想要变成响应式的 对象数据 当成参数传入
setup -> const state = reactive({name:'张一一'})
  • 如果想要在模块中使用,必须 return

注意事项

  • 在使用 reactive 函数的时候,必须传入一个对象 {name:'张一一'}

代码演示

<template>
  <div>
    {{state.name}} // 使用插值表达式引用
  </div>
</template>

<script>
import {reactive} from 'vue'
export default {
  name: 'App',
  setup(){
    const state = reactive({
      name:'张一一'
    })
    setTimeout(() => {
      state.name = '冯家祺'
    },2000)
    return{
      state
    }
  }
}
</script>

ref

作用

ref 是一个可执行的函数,接受一个简单类型或复杂类的传入,并返回一个响应式,且可变的 ref 对象

使用步骤

  • vue 框架中导入 ref 函数
  • setup 函数中调用 ref 函数并传入数据(简单类型或复杂类型)
  • setup 函数中把 ref 函数调用完毕的返回值以对象的形式返回出去
  • setup 函数是使用 ref 结果,需要通过 .value 访问,在模板中使用不需要加 .value

代码演示

<template>
  <div>
    {{msg}} // 不需要加 .value
    {{list}}
  </div>
</template>

<script>
import {ref} from 'vue'
export default {
  name: 'App',
  setup(){
    const msg =ref('张一一')
    const list = ref ([1,2,3])
    setTimeout(() => {
      list.value.push(4,5,6) // 一定要加 .value
    },2000)
    return{
      msg,
      list
    }
  }
}
</script>

reative 对比 ref

  • ref 函数可以接收一个简单类型的值,返回一个可改变的 ref 响应式对象,从而弥补 reactive 函数不支持简单类型的问题
  • reactiveref 函数都可以提供响应式数据的转换,具体什么时候使用哪个API社区还没有最佳实践
  • 推荐写法 只有我们明确知道要转换的对象内部的字段名称(例如:form表单),我么才使用 reactive,否则一律使用 ref,从而降低在语法选择上的心智负担

computed

什么是计算属性

  • 特征:基于一个现有的响应式数据,经过一定的计算得到一个全新的数据,并且依赖的数据一旦发生改变,就会立即重新计算得到新值

  • 优势:缓存,模板中如果多次使用,只会在第一次使用的时候执行一次函数,后面都会使用缓存

使用步骤

  • vue 框架中导入computed 函数
  • setup 函数中执行 computed 函数,并传入一个函数,在函数中定义计算公式
  • computed 函数调用完的返回值放到 setup 函数 return 出去的对象中 注意:一定要 return

代码演示

<template>
  <div>
    {{list}}
    {{filterList}}
  </div>
  
</template>

<script>
import {ref,computed} from 'vue'
export default {
  name: 'App',
  setup(){
    // 原始数据
    const list = ref([1,2,3,4,5])
    // 计算属性
    const filterList = computed(() => {
      // 基于list筛选出所有大于2的项 返回一个新数组
      return list.value.filter(item => item > 2)
    })
    // 修改原数组 观察 计算属性
    setTimeout(() => {
      list.value.push(7,8,9)
    },2000)
    return{
      list,
      filterList
    }
  }
}
</script>

<style>

</style>

watch

作用

监听一个实例属性的变化然后执行一个回调,和 vue2 中的 watch 的功能一致

使用步骤

  • vue 框架中导入 watch 函数
  • setup 函数中执行 watch 函数,开启对响应式数据的监听
  • watch 接收三个常规参数
    1. 第一个参数为函数,返回你要的监听变化的响应书数据
    2. 第二个参数为响应式数据变化之后要执行的回调函数
    3. 第三个参数为一个对象,在里面配置是否开启 立即执行深度监听

普通监听

数据变化 执行回调

代码演示

<template>
  {{ age }}
  <button @click="age++">change age</button>
</template>

<script>
import { ref, watch } from 'vue'
export default {
  setup() {
    const age = ref(18)
    watch(() => {
      // return 监听的数据
      return age.value
    }, () => {
      // 数据变化之后的回调函数
      console.log('age发生了变化')
    })
    return {
      age
    }
  }
}
</script> 

立即执行

一上来先执行一次,数据变化后再执行一次

watch的效果默认状态下,只有监听的数据发生变化才会执行回调,如果你需要在一上来的时候就立刻执行一次,需要配置一下immediate属性(第三个参数)

代码演示

<template>
  {{ age }}
  <button @click="age++">change age</button>
</template>
<script>
import { ref, watch } from 'vue'
export default {
  setup() {
    const age = ref(18)
    watch(() => {
      // return 监听的数据
      // 返回你想要监听的响应式属性(ref产生的对象必须加.value)
      return age.value
    }, () => {
      // 数据变化之后的回调函数
      console.log('age发生了变化')
    },{ immediate: true})
    return {
      age
    }
  }
}
</script> 

深度监听

  • 对象如果嵌套层级比较深,不管哪个属性变化,都会触发回调
  • 默认情况下,没有开启深度监听,对象属性的修改不会引起回调执行
  • 建议大家大多数情况不要开启深度监听,递归处理比较耗性能,推荐使用精确监听

当我们监听的数据是一个对象的时候,默认状态下,对象内部的属性发生变化是不会引起回调函数执行的,如果想让对象下面所有属性都能得到监听,需要开启deep配置

代码演示

<template>
  {{ state.name }}
  {{ state.info.age }}
  <button @click="name = 'pink'">change name</button>
  <button @click="info.age++">change age</button>
</template>

<script>
import { reactive, toRefs, watch } from 'vue'
export default {
  setup() {
    const state = reactive({
      name: 'cp',
      info: {
        age: 18
      }
    })
    watch(() => {
      return state
    }, () => {
      // 数据变化之后的回调函数
      console.log('age发生了变化')
    }, {
      deep: true
    })
    return {
      state
    }
  }
}
</script> 

优化

使用 watch 的时候,尽量详细的表明你到底要监听哪个属性,避免使用 deep引起的性能问题,比如我仅仅只是想在 state 对象的 age 属性变化的时候执行回调,可以这么写

<template>
  {{ state.name }}
  {{ state.info.age }}
  <button @click="state.name = 'pink'">change name</button>
  <button @click="state.info.age++">change age</button>
</template>

<script>
import { reactive, toRefs, watch } from 'vue'
export default {
  setup() {
    const state = reactive({
      name: 'cp',
      info: {
        age: 18
      }
    })
    watch(() => {
      // 详细的告知你要监听谁
      return state.info.age
    }, () => {
      // 数据变化之后的回调函数
      console.log('age发生了变化')
    })
    return {
      state
    }
  }
}
</script>