性能的提升

  • 打包大小减少 按需加载 tree shake
  • 初次渲染加快 重写虚拟 dom
  • 内存使用减小 Proxy 代替 Object.defineProperty

解决的痛点

多行代码组件难维护

原来是一个功能在 data 在 computer 在 methods 中等等地方分开

现在是一个功能就是放在一个地方来开发

正所谓鸡蛋不能放在一个篮子里面

所有的 data, prop method 等数据都在一个篮子里面, 包死

Composition API

  • ref, reactive
  • computed, watch
  • 新的生命周期函数
  • 自定义 Hooks 像 React
  • Teleport
  • Suspense
  • 全局 API 的优化和修改
  • 更好的 TS 支持

API 的区别

原来是 options API 现在是 Composition API


// options API

data() {},

methods: {},

computed: {},

mounted() {},

xxx: {}



composition API

ref

使用



<div>

    <h1>Count is :{{count}}</h1>

    <h2>Double is {{double}}</h2>

    <button @click="increase" >Click To Add Count</button>

    <button @click="clearCount" >Click To Clear Count</button>

</div>



import { ref, computed } from 'vue'


export default {

    name: "TestAdd",

    setup() {

        const count = ref(0)

        const double = computed(() => count.value * 2)

        const increase = () => {

            count.value++

        }

        const clearCount = () => {

            count.value = 0 // 在其他地方读取数据,需要在原数据中加一个 value属性

        }

        return {

            count,

            increase,

            clearCount,

            double

        }

    }

}

</script>

reactive


setup() {

    const data = reactive({

        count: 0,

        increase: () => data.count++,

        double: computed(() => data.count*2) // 这里double中computed回调使用了data的count,类型推论不了 在ts中加一个接口也可以

    })

    return {

        data // 这里如果用 xx = data.xx 是不可以的。看下面的解释

        // 在template中要 使用 data.count 等属性 不方便

    }

}

toRefs

Vue3 使用 Proxy 之后,许多解构的东西都变得不响应式了,比如上面的 data 中,如果使用扩展运算符或者直接赋值,都是不可以用的


interface DataProps {

    count: number;

    increase: () => void;

    double: number;

    clearCount: () => void;

}

setup() {

    const data: DataProps = reactive({

        count: 0,

        increase: ()=> data.count++,

        double: computed(() => data.count * 2),

        clearCount: () => {data.count = 0}

    })

    const refData = toRefs(data)

    return {

        ...refData   // 在template中可以不加data了

    }

}

Object.defineProperty VS Proxy


Object,defineProperty(data, 'keyName', {

    get() {},

    ser() {}

})


new Proxy(data, {

    get(keyName) {},

    set(keyName, value) {}

})

生命周期差异

周期函数图

// Vue2 到 Vue3 的变化

beforeCreated -> use setup()

created -> use setup()

beforeMount -> onBeforeMount

mounted -> onMounted

beforeUpdate -> onbeforeUpdate

updated -> onUpdated

destroyed -> onUnmounted

activated -> onActivated

deactivated -> onDeactivated

errorCaptured -> onErrorCaptuere

// 新增

onRenderTracked

onRenderTriggered

用法:


setup() {

    ...

    mounted(() => {

        ...actions

    })

    //  首先要导入,然后调用周期函数,传入回调,回调会被执行

    //  这里有一点注意的是 ,不知道哪些是不在setup函数内的(仅我不知道) 

}

onRenderTriggered

在渲染的时候 调试

Watch

Wacth和上面的生命周期 都是在setup函数中使用的

如果watch多个值,第一个参数传一个数组 [xxx, aaaa] 这样的

函数内有两个参数,第一个是监听的 ref或reactive函数生成的值 然后第二个是个回调 参数分别是新值和旧值


setup() {

    const a = ref('')

    watch(a, (newV,oldV) => {

        // ...

    })

}

在这里有一点 ,如果watch中的参数(不管是数组还是单个值) 都必须是响应式的


const daat = reactive({

    count:0

})

上述data是响应式的,可以直接作为Watch的参数,但是data中的count是一个静态的数字类型,并不能响应式,如果想要响应式,可以这样


watch([a, () => data.count], (newV, oldV)=> {

    // actions

})

// 可以做一个匿名函数来将它返回,这样,这个值也会变成响应式的了 (就是不知道为啥)

teleport

在template中使用 teleport标签


<teleport to="#model"></teleport>

然后在public中的index.html中 id为app的div下面,增加一个id为model的div

some 傻逼思考


// shared function

const isPromise = <T = any>(val: unknown): val is Promise<T> => {

    return isObject(val) && isFunction(val.then) && isFunction(val.catch)

}


// resolveData function

if (__DEV__ && isPromise(data)) {

    warn(

        `data() returned a Promise - note data() cannot be async; If you ` +

        `intend to perform data fetching before component renders, use ` +

        `async setup() + <Suspense>.`

    )

}


在Vue3源码中随便翻到的片段,让我不禁想到,如果在data函数中加入then和catch函数,是不是就会被判断成是一个Promise呢?

尝试了,不可以

因为data在ts中类型被定义好了,不可以有这些东西,

还挺牛逼

emit

首先 命名不能是驼峰,得是kebab-case

父节点的templa中 @emit-name 发布一个函数

然后子组件订阅的时候就会触发父组件中发布的函数


// parent.vue

html

    button @emit-name="someFunc"

script

    methods or setup function

    setup() {

        const someFunc  = () {

            // ... some action  这里的函数名字要和template中的名字一样

        }

        return {

            someFunc

        }

    }


// child.vue

script

    setup(props, context) {

        ChildFunc() {

            context.emit('emit-name') // 当触发了ChildFunc的时候,父组件的someFunc会被触发,执行someFunc的动作

        }

    }

与vue2的区别

快忘记了。。 先捋一捋

最后修改:2020 年 10 月 04 日 11 : 55 PM
如果觉得我的文章对你有用,请随意赞赏