Notices of the Composition API

2019/11/23

v-kansai mokumoku #3

2019/12/16

v-okinawa #3

jiyuujin

  • Vue/Nuxt/PHP/Scala/Java/Swift
  • v-kansai/kansai.ts/..
  • Web猫ブログ (webneko.dev)

Composition API

How do you write Vue/TS?

The more you go down,

it doesn't look like Vue

  • Vue.extend
  • Class component
  • vue-property-decorator
  • @vue/composition-api

Final RFC for Vue3!!!

You can also use the api,

in business projects

Install & Prepare

Install @vue/composition-api

Register as a plugin

import Vue from 'vue'
import CompositionApi from '@vue/composition-api'

Vue.use(CompositionApi)

Import a registered plugin

import '@/plugins/composition-api.ts'

That's all!

At first, we can do this!

Not much different as usual

  • HTML, script, and style as usual
  • Easier to use TS, also use TSX not dividing a template
  • Caution to enlargement of base fn (setup)

HowTo Use in a Component

createComponent class

import { createComponent, SetupContext } from '@vue/composition-api'

export default createComponent({
    //
})

Base fn - setup

import { createComponent, SetupContext } from '@vue/composition-api'

export default createComponent({
    setup(props: {}, ctx: SetupContext) {
        return (
            //
        )
    }
})

setup fn - arguments

  • props (Object type)
  • ctx (SetupContext)

props (Object type)

Set the object type for props

import { createComponent, SetupContext } from '@vue/composition-api'

interface PropsType {
    participants: number,
    mealName: string
}

export default createComponent({
    setup(props: PropsType, ctx: SetupContext) {
        //
    }
})

ctx (SetupContext)

Type definitions of SetupContext

interface Data {
  [key: string]: unknown
}

interface SetupContext {
  attrs: Data
  slots: Slots
  parent: ComponentInstance | null
  root: ComponentInstance
  emit: ((event: string, ...args: unknown[]) => void)
}

function setup(
  props: Data,
  context: SetupContext
): Data

To get route params, use ctx.root.$route

Get route parameters by SetupContext

import { createComponent, SetupContext } from '@vue/composition-api'

export default createComponent({
    setup(props: {}, ctx: SetupContext) {
        // Get Route Params
        const param = ctx.root.$route.params;
    }
})

In global managed, use ctx.root.$store

Get state by SetupContext

import { createComponent, SetupContext } from '@vue/composition-api'

export default createComponent({
    setup(props: {}, ctx: SetupContext) {
        // Get state
        const userStatus = ctx.root.$store.state.product.userStatus

        // Use computed api
        const filteredUserStatus = computed(
            () => ctx.root.$store.state.product.userStatus
        )
    }
})

others..

HowTo set instance variables

  • (data)
  • ref
  • reactive

Use instance variables by data

import Vue from 'vue'

export default Vue.extend({
    data() {
        return {
            participants: 12,
            meals: ['hamburger', 'ramen', 'pizza']
        }
    }
})

Use reactive variables by ref

import { createComponent, SetupContext } from '@vue/composition-api'

export default createComponent({
    setup(props: {}, ctx: SetupContext) {
        const participants = ref(12)
        const meals = ref(['hamburger', 'ramen', 'pizza'])
    }
})

Set a single reactive dataset with refs

import { createComponent, SetupContext } from '@vue/composition-api'

export default createComponent({
    setup(props: {}, ctx: SetupContext) {
        const ReactiveData = reactive({
            participants: 12,
            meals: ['hamburger', 'ramen', 'pizza']
        })
    }
})

ref vs reactive

  • Use object type in reactive
  • Put higher related elements in reactive
  • The other side, put the independence element in ref

One another..

Don't forget "return"

import { createComponent, SetupContext } from '@vue/composition-api'

export default createComponent({
    setup(props: {}, ctx: SetupContext) {
        return {
            state
        }
    }
})

unless, you can't use variables in a template..😅

Wanna Prevent Enlargement

Directories in Vue CLI

  • views
  • components
  • compositions
  • repositories

views

import { createComponent, SetupContext } from '@vue/composition-api'

export default createComponent({
    setup(props: {}, ctx: SetupContext) {
        return (
            //
        )
    }
})

Load other components

import { createComponent, SetupContext } from '@vue/composition-api'

const AtomsButton = () => import('@/components/AtomsButton.vue')

export default createComponent({
    components: {
        AtomsButton
    },
    setup(props: {}, ctx: SetupContext) {
        return (
            //
        )
    }
})

compositions

  • Mainly use logic, not related to UI
  • Inherent fn to the view

Several methods..👎

import Vue from 'vue'

export default Vue.extend({
    methods: {
        increment() {
            //
        },
        decrement() {
            //
        }
    }
})

Ummm, not bad..😕

import { createComponent, SetupContext } from '@vue/composition-api'

export default createComponent({
    const increment = () => {
        //
    }
    const decrement = () => {
        //
    }
    setup(props: {}, ctx: SetupContext) {
        return (
            increment,
            decrement
        )
    }
})

Easier to see..👍

import { createComponent, SetupContext } from '@vue/composition-api'

import { increment, decrement } from '@/compositions'

export default createComponent({
    setup(props: {}, ctx: SetupContext) {
        return (
            increment,
            decrement
        )
    }
})

repositories

  • Use APIs
  • Access to external resources

Mix in a component..👎

import Vue from 'vue'

export default Vue.extend({
    methods: {
        async fetchApi() {
            await ..
        }
    }
})

Ummm, not bad..😕

import { createComponent, SetupContext, onMounted } from '@vue/composition-api'

export default createComponent({
    const fetchApi = async () => {
        await ..
    }
    onMounted(async () => {
        await fetchApi()
    })
    setup(props: {}, ctx: SetupContext) {
        return (
            //
        )
    }
})

Easier to see..👍

import { createComponent, SetupContext } from '@vue/composition-api'

import { fetchApi } from '@/repositories'

export default createComponent({
    setup(props: {}, ctx: SetupContext) {
        return (
            fetchApi
        )
    }
})

Wanna vuex store

This time, omitted..🙏

Really, is it necessary..?

  • Do u think about the system design?
  • Can you make use of props?
  • Create a plugin from the perspective of DI

That aside.. 🤔

What something in trouble?

Something in trouble..

  • No existed "asyncData" api
  • Cannot use the "component" tag
  • ..

Wanna use"asyncData" api in a component

  • No existed.. 😱
  • Use "fetch" api instead of the api

Route params before rendering

import { createComponent, SetupContext } from '@vue/composition-api'

export default createComponent({
    fetch({ route }) {
        console.log(route.params)
    },
    setup(props: {}, ctx: SetupContext) {
        return (
            //
        )
    }
})

Store actions before rendering

import { createComponent, SetupContext } from '@vue/composition-api'

export default createComponent({
    fetch({ store }) {
        store.dispatch('fetchAction')
    },
    setup(props: {}, ctx: SetupContext) {
        return (
            //
        )
    }
})

Can u use the "component" tag, in Vue/TSX

i don't know

Under investigating.. 🤔

Do u understand what it's..?

<template>
    <component
        :is="svg"
        style="width: 16px;"
    />
</template>

<script lang="ts">
import Vue from 'vue'

export default Vue.extend({
    props: {
        name: {
            type: String,
            required: true
        }
    },
    computed: {
        svg() {
            return () => import(`@/assets/img/${this.name}.svg`)
        }
    }
})
</script>

Not working in TSX.. 😭

import { createComponent, SetupContext } from '@vue/composition-api'

type SvgProps = {
    name: string
}

export default createComponent({
    props: {
        name: {
            type: String,
            required: true
        }
    },
    setup(props: SvgProps, ctx: SetupContext) {
        const svg = () => import(`@/assets/img/${props.name}.svg`)

        return () => (
            <component is={svg} style="width: 16px;" />
        )
    }
})

Give up TSX, exchange to divide a template

Basically, we can use the composition api in Vue/TSX

Divide a template as usual

<template>
    <component
        :is="svg"
        style="width: 16px;"
    />
</template>

<script lang="ts">
import { createComponent, SetupContext } from '@vue/composition-api'

type SvgProps = {
    name: string
}

export default createComponent({
    props: {
        name: {
            type: String,
            required: true
        }
    },
    setup(props: SvgProps, ctx: SetupContext) {
        const svg = () => import(`@/assets/img/${props.name}.svg`)

        return () => (
            svg
        )
    }
})
</script>

Not yet, developing.. 🤔🤔🤔

Easier to write Vue/TS

Easier to use TSX in Vue..?

Vue Advent Calendar 2019

Also use Vue/TSX in 12/24..🎁

Thank you..🙇‍♀️

Made with Slides.com