vue3实践,从setup与ref(),reactive(),toRefs()谈起

1,935 阅读3分钟

写在前文vue3.2不久前发布,那么对于处于一线的前端工程师,有必要将vue2升级到vue3,迎接全新出现的composition API?

安装最新的@vue/cli

npm install -g @vue/cli

然后使用命令行

vue create hello-vue3 项目名称
<template>
  <div>
      <el-button @click="add">Add </el-button>
      <div v-for="(item,index) in listArray" :key="index">
        <el-input v-model="item.value" placeholder="请输入内容" class="item"></el-input>
        <i class="el-icon-close" @click="remove(index)"></i>
      </div>
  </div>
</template>

我们来使用vue3的组合式api也是就是composition API来实现上述功能

<script>
import {ref} from "vue"
export default {
  setup() {
    //初始化数组
    const listArray = ref([{value:1},{value:2},{value:3}])
    //add
    const add = ()=>{
      listArray.value.push({value:""})
    }
    //remove
    const remove =(index)=>{
      console.log(index)
      listArray.value.splice(index,1)
    }
    console.log(listArray.value)
    return {listArray,add,remove}
  },
}

</script>

相较于vue2的options-api来说,

我们对setup和ref做一个总结

setup函数是一个生命周期钩子对应的其实是vue2中的beforeCreate和create,并且他是vue3的composition API的入口函数,在vue3 我们通过这个函数来定义vue2中的data,methods,watch,computed属性,setup函数必须有返回值,必须返回一个对象,对象里包含所有在template模板中需要使用到的属性。

ref

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

取值和赋值的时候要通过.value方法去拿,但是template却不使用.value,steup接收两个参数props和context,在js里这个形参代表上下文,暴露组件的property,后者可以拿到

有的人不喜欢这种通过.value还有返回多个值出去在模板或在setup里使用,我们可以使用reative()

用data 将我们需要返回的属性和方法包裹起来再返回

<script>
import {reactive} from "vue"
export default {
  setup(props,context) {
    console.log(props)
    console.log(context)
    const data = reactive({
      listArray:[{value:1},{value:2},{value:3}],
      add:()=>{
        data.listArray.push({value:''})
      },
      remove:(index)=>{
        data.listArray.splice(index,1)
      }
    })
    return {data}
  },
}
</script>

但是这样有一个问题,在模板中使用,我们需要通过data.xxx来调用属性和方法,

我们很自然很想到能否对他解构赋值,

我们可以通过toRefs()将data元素解构,这样的话,我们直接拿到属性和方法。

<template>
  <div>
      <el-button @click="add">Add </el-button>
      <div v-for="(item,index) in listArray" :key="index">
        <el-input v-model="item.value" placeholder="请输入内容" class="item"></el-input>
        <i class="el-icon-close" @click="remove(index)"></i>
      </div>
  </div>
</template>
<script>
import {reactive,toRefs} from "vue"
export default {
  setup(props,context) {
    // //初始化数组
    const data = reactive({
      listArray:[{value:1},{value:2},{value:3}],
      add:()=>{
        data.listArray.push({value:''})

      },
      remove:(index)=>{
        data.listArray.splice(index,1)
      }
    })
    const result = toRefs(data)
    return {...result}
  },
}
</script>

Vue3的生命周期

正如官方文档所说,setup()取代之前的beforeCreate()和created生命周期函数,其余生命周期函数放在setup()实现。

computed与watch

computed

接受一个 getter 函数,并根据 getter 的返回值返回一个不可变的响应式 ref 对象。或者,接受一个具有 getset 函数的对象,用来创建可写的 ref 对象。

    const count =  ref(1)
    const count2 =  ref(2)
    const plusOne = computed(()=> count.value+1)
    console.log('plusOne:'+plusOne.value)//2
    //plusOne.value++ 
    const plusTwo = computed({
      get:()=>count2.value+1,
      set:val=>{
        count2.value = val-1
      }
    })
    console.log('plusTwo:'+plusTwo.value)//3
    console.log(plusTwo.value++)//3

watch

为了根据响应式状态自动应用重新应用副作用,我们可以使用 watchEffect 方法。它立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。

const count = ref(0)
watchEffect(() => console.log(count.value))
// -> logs 0
setTimeout(() => {
  count.value++
  // -> logs 1

}, 100)

watch API 完全等同于组件侦听器 property。watch 需要侦听特定的数据源,并在回调函数中执行副作用。默认情况下,它也是惰性的,即只有当被侦听的源发生变化时才执行回调。

  • watchEffect 比较,watch 允许我们:

    • 懒执行副作用;
  • 更具体地说明什么状态应该触发侦听器重新运行;
  • 访问侦听状态变化前后的值。
// 侦听一个 getter
const state = reactive({ count: 0 })
watch(
  () => state.count,
  (count, prevCount) => {
    /* ... */
  }

)
// 直接侦听ref

const count = ref(0)
watch(count, (count, prevCount) => {
  /* ... */
})

但是从设计上相较于React hooks函数式编程对react 16.8以往的class 升级,从语法上我觉得不够简洁,以后会写篇文章对比下,vue 3 composition API生命周期函数依然存在,各种ref api,多了选择,但是也给代码风格统一带来了困难,options API确实存在种种问题,但是也保证了下限。我认为对于目前的vue2项目可以尝试@vue/composition-api,不妨自己动手写下看看效果如何,再考虑是否对项目进行大版本升级。

参考

Vue 3 官方文档