Taste the new features of vue3.x - Composition API

Original address http://www.liulongbin.top:8085

0. Basic requirements

  1. Understanding common ES6 new features
    • ES6 import and export grammar
    • Destructuring assignment
    • Arrow function
    • etc...
  2. Understanding the basic use of vue 2.x
    • assembly
    • Commonly used instructions
    • Life cycle function
    • computed, watch, ref, etc.

1. Relevant resources

  • [Know - Vue Function-based API RFC] https://zhuanlan.zhihu.com/p/68477600
  • [github - vuejs/composition-api]https://github.com/vuejs/composition-api
  • [github - composition-api/CHANGELOG.md]https://github.com/vuejs/composition-api/blob/master/CHANGELOG.md
  • [Open Source China-Youyuxi Publishes the Vue 3.0 Development Route: Rewriting 3.0 from scratch] https://www.oschina.net/news/100515/plans-for-the-next-iteration-of-vue-js

2. Initialization project

  1. Install vue-cli3

    npm install -g @vue/cli
    # OR
    yarn global add @vue/cli
  2. Create project

    vue create my-project
    # OR
    vue ui
  3. Install composition-api in the project to experience new features of vue3

    npm install @vue/composition-api --save
    # OR
    yarn add @vue/composition-api
  4. Before using any @vue/composition-api capabilities, you must install them through Vue.use().

    import Vue from 'vue'
    import VueCompositionApi from '@vue/composition-api'
    
    Vue.use(VueCompositionApi)

    After installing the plug-in, you can use the new one Composition API It's time to develop components.

3. setup

The setup() function is a new property specifically provided for components in vue3. It provides a unified entry point for us to use the new features of the Composition API of vue3.

3.1 Opportunity for Implementation

The setup function is executed after before Create and before Create.

3.2 Receiving props data

  1. Define in props the name of the parameter that the current component allows to be passed from the outside world:

    props: {
        p1: String
    }
  2. The props data is received by the first parameter of the setup function:

    setup(props) {
        console.log(props.p1)
    }

3.3 context

The second parameter of the setup function is a context object, which contains some useful attributes that need to be accessed through this in vue 2.x. In vue 3.x, they are accessed as follows:

const MyComponent = {
  setup(props, context) {
    context.attrs
    context.slots
    context.parent
    context.root
    context.emit
    context.refs
  }
}

Note: this cannot be accessed in the setup() function

4. reactive

The reactive() function receives a common object and returns a responsive data object.

4.1 Basic Grammar

Equivalent to the Vue.observable() function in vue 2.x, the reactive() function in vue 3.x is provided to create responsive data objects. The basic code examples are as follows:

import { reactive } from '@vue/composition-api'

// Create a responsive data object that yields a state similar to that returned by data() in vue 2.x
const state = reactive({ count: 0 })

4.2 Define responsive data for template use

  1. Import the reactive function on demand:

    import { reactive } from '@vue/composition-api'
  2. In the setup() function, call the reactive() function to create the response data object:

    setup() {
         // Creating responsive data objects
     const state = reactive({count: 0})
    
         // return the responding data object in the setup function for template use
     return state
    }
  3. Access response data in template:

    <p> The current count value is: {count}</p>

5. ref

5.1 Basic Grammar

The ref() function is used to create a responsive data object based on the given value. The return value of the ref() function call is an object, which contains only one. Value attribute:

import { ref } from '@vue/composition-api'

// Create a responsive data object count with an initial value of 0
const count = ref(0)

// If you want to access the value of the responsive data object created by ref(), you must pass the. Value attribute.
console.log(count.value) // Output 0
// Let count + 1
count.value++
// Print count again
console.log(count.value) // Output 1

5.2 Accessing the responsive data created by ref in template

  1. Create responsive data in setup():

    import { ref } from '@vue/composition-api'
    
    setup() {
     const count = ref(0)
    
         return {
             count,
             name: ref('zs')
         }
    }
  2. Access response data in template:

    <template>
     <p>{{count}} --- {{name}}</p>
    </template>

5.3 Accessing the responsive data created by ref in the reactive object

When the responding data object created by ref() is mounted on reactive(), it automatically expands the responding data object into the original value, which can be accessed directly without passing. value, for example:

const count = ref(0)
const state = reactive({
  count
})

console.log(state.count) // Output 0
state.count++            // There is no need to go through. value to access the original value directly.
console.log(count)       // Output 1

Note: The new ref overrides the old Ref. The sample code is as follows:

// Create ref and mount it into reactive
const c1 = ref(0)
const state = reactive({
  c1
})

// Create ref again, named c2
const c2 = ref(9)
// Replace old ref c1 with new ref c2
state.c1 = c2
state.c1++

console.log(state.c1) // Output 10
console.log(c2.value) // Output 10
console.log(c1.value) // Output 0

6. isRef

isRef() is used to determine whether a value is an object created by ref(); application scenario: when it is necessary to expand a value that may be created for ref(), for example:

import { isRef } from '@vue/composition-api'

const unwrapped = isRef(foo) ? foo.value : foo

7. toRefs

The toRefs() function converts reactive() created responsive objects into ordinary objects, except that each attribute node on this object is ref() type responsive data. The most common application scenarios are as follows:

import { toRefs } from '@vue/composition-api'

setup() {
    // Define responsive data objects
    const state = reactive({
      count: 0
    })
    
    // Define the event handlers available on the page
    const increment = () => {
      state.count++
    }
    
    // Return an object in setup for page use
    // This object can contain either responsive data or event handlers.
    return {
      // Converting each attribute on state to ref-like responsive data
      ...toRefs(state),
      // Self-Increasing Event Handling Functions
      increment
    }
}

The response data return ed from setup() can be accessed directly on the page:

<template>
  <div>
    <p>Current count The value is:{{count}}</p>
    <button @click="increment">+1</button>
  </div>
</template>

8. computed

computed() is used to create computational properties, and the return value of the computed() function is an instance of ref. You need to import on demand before using computed:

import { computed } from '@vue/composition-api'

8.1 Create read-only computational properties

During the call of the computed() function, a function function function is passed in, and a read-only computing property can be obtained. The sample code is as follows:

// Create a ref responsive data
const count = ref(1)

// Create a responsive computational attribute plusOne based on the value of count
// It automatically calculates and returns a new ref based on the dependent ref
const plusOne = computed(() => count.value + 1)

console.log(plusOne.value) // Output 2
plusOne.value++            // error

8.2 Create Readable and Writable Computing Properties

During the call of the computed() function, an object containing get and set functions is passed in, and a readable and writable computing property can be obtained. The sample code is as follows:

// Create a ref responsive data
const count = ref(1)

// Create a computed computational property
const plusOne = computed({
  // Value function
  get: () => count.value + 1,
  // Assignment function
  set: val => { count.value = val - 1 }
})

// The set function is triggered for the operation of calculating attribute assignment
plusOne.value = 9
// When the set function is triggered, the count value is updated
console.log(count.value) // Output 8

9. watch

The watch() function is used to monitor changes in certain data items, triggering certain operations that need to be imported on demand before they are used:

import { watch } from '@vue/composition-api'

9.1 Basic usage

const count = ref(0)

// Define watch, which triggers a watch callback whenever the count value changes
// watch is automatically invoked once when it is created
watch(() => console.log(count.value))
// Output 0

setTimeout(() => {
  count.value++
  // Output 1
}, 1000)

9.2 Monitor Designated Data Sources

Monitor data sources of type reactive:

// Define data sources
const state = reactive({ count: 0 })
// Monitor the change of the state.count data node
watch(() => state.count, (count, prevCount) => { /* ... */ })

Monitor data sources of ref type:

// Define data sources
const count = ref(0)
// Specify the data source to be monitored
watch(count, (count, prevCount) => { /* ... */ })

9.3 Monitor Multiple Data Sources

Monitor data sources of type reactive:

const state = reactive({ count: 0, name: 'zs' })

watch(
  [() => state.count, () => state.name],    // Object.values(toRefs(state)),
  ([count, name], [prevCount, prevName]) => {
    console.log(count)         // New count value
    console.log(name)          // New name value
    console.log('------------')
    console.log(prevCount)     // Old count value
    console.log(prevName)      // New name value
  },
  {
    lazy: true // When a watch is created, the code in the callback function is not executed
  }
)

setTimeout(() => {
  state.count++
  state.name = 'ls'
}, 1000)

Monitor data sources of ref type:

const count = ref(0)
const name = ref('zs')

watch(
  [count, name], // Multiple ref data sources that need to be monitored
  ([count, name], [prevCount, prevName]) => {
    console.log(count)
    console.log(name)
    console.log('-------------')
    console.log(prevCount)
    console.log(prevName)
  },
  {
    lazy: true
  }
)

setTimeout(() => {
  count.value++
  name.value = 'xiaomaolv'
}, 1000)

9.4 Clearance Surveillance

Watch monitoring created in the setup() function automatically stops when the current component is destroyed. If you want to stop a monitor explicitly, you can call the return value of the watch() function. The grammar is as follows:

// Create a monitor and get a stop function
const stop = watch(() => { /* ... */ })

// Call the stop function to clear the corresponding monitoring
stop()

9.5 Clear Invalid Asynchronous Tasks in watch

Sometimes, when the value monitored by the watch changes, or after the watch itself is stop ped, we expect to be able to clean up those invalid asynchronous tasks. At this point, a cleanup registrator function is provided in the watch callback function to perform the cleanup. This cleanup function is called in the following cases:

  • watch is repeated
  • watch was forced to stop

The code example in Template is as follows:

/* template Code in */
<input type="text" v-model="keywords" />

The code examples in Script are as follows:

// Define responsive data keywords   
const keywords = ref('')

// Asynchronous Tasks: Printing User Input Key Words
const asyncPrint = val => {
  // Print after 1 second delay
  return setTimeout(() => {
    console.log(val)
  }, 1000)
}

// Define watch listening
watch(
  keywords,
  (keywords, prevKeywords, onCleanup) => {
    // Execute asynchronous tasks and get timerId to turn off asynchronous tasks
    const timerId = asyncPrint(keywords)

    // If the watch listener is repeated, the last unfinished asynchronous task is cleared first
    onCleanup(() => clearTimeout(timerId))
  },
  // watch is not executed when it was first created
  { lazy: true }
)

// return the data needed in the template
return {
  keywords
}

10. LifeCycle Hooks

The new version of life cycle functions can be imported into components on demand and can only be used in setup() functions. The code examples are as follows:

import { onMounted, onUpdated, onUnmounted } from '@vue/composition-api'

const MyComponent = {
  setup() {
    onMounted(() => {
      console.log('mounted!')
    })
    onUpdated(() => {
      console.log('updated!')
    })
    onUnmounted(() => {
      console.log('unmounted!')
    })
  }
}

The following list is the mapping between the life cycle function of vue 2.x and the new version of Composition API:

  • beforeCreate -> use setup()
  • created -> use setup()
  • beforeMount -> onBeforeMount
  • mounted -> onMounted
  • beforeUpdate -> onBeforeUpdate
  • updated -> onUpdated
  • beforeDestroy -> onBeforeUnmount
  • destroyed -> onUnmounted
  • errorCaptured -> onErrorCaptured

11. provide & inject

provide() and inject() can achieve data transfer between nested components. These two functions can only be used in setup() functions. The parent component uses the provide() function to pass data downward; the child component uses inject() to get the data passed from the upper layer.

11.1 Sharing Common Data

App.vue root component:

<template>
  <div id="app">
    <h1>App Root components</h1>
    <hr />
    <LevelOne />
  </div>
</template>

<script>
import LevelOne from './components/LevelOne'
// 1. Import provide on demand
import { provide } from '@vue/composition-api'

export default {
  name: 'app',
  setup() {
    // 2. App root component acts as parent component, sharing data to child component through provide function (unlimited level)
    //    provide('the name of the data to be shared', the data to be shared)
    provide('globalColor', 'red')
  },
  components: {
    LevelOne
  }
}
</script>

LevelOne.vue component:

<template>
  <div>
    <!-- 4. Set font color for labels by property binding -->
    <h3 :style="{color: themeColor}">Level One</h3>
    <hr />
    <LevelTwo />
  </div>
</template>

<script>
import LevelTwo from './LevelTwo'
// 1. Import inject as needed
import { inject } from '@vue/composition-api'

export default {
  setup() {
    // 2. When the inject function is called, the data shared by the parent is obtained by the specified data name.
    const themeColor = inject('globalColor')
    
    // 3. return the shared data received to Template for use
    return {
      themeColor
    }
  },
  components: {
    LevelTwo
  }
}
</script>

LevelTwo.vue component:

<template>
  <div>
    <!-- 4. Set font color for labels by property binding -->
    <h5 :style="{color: themeColor}">Level Two</h5>
  </div>
</template>

<script>
// 1. Import inject as needed
import { inject } from '@vue/composition-api'

export default {
  setup() {
    // 2. When the inject function is called, the data shared by the parent is obtained by the specified data name.
    const themeColor = inject('globalColor')

    // 3. return the shared data received to Template for use
    return {
      themeColor
    }
  }
}
</script>

11.2 Sharing ref responsive data

The following code realizes the function of point button to switch theme color. It mainly modifies the code in App.vue component. The code in LevelOne.vue and LevelTwo.vue is unchanged.

<template>
  <div id="app">
    <h1>App Root components</h1>
    
    <!-- click App.vue The button in the sub-component to switch the color of the text in the sub-component -->
    <button @click="themeColor='red'">Red</button>
    <button @click="themeColor='blue'">blue</button>
    <button @click="themeColor='orange'">Orange</button>

    <hr />
    <LevelOne />
  </div>
</template>

<script>
import LevelOne from './components/LevelOne'
import { provide, ref } from '@vue/composition-api'

export default {
  name: 'app',
  setup() {
    // Define ref responsive data
    const themeColor = ref('red')
    
    // Use ref data through subcomponents provided by provide
    provide('globalColor', themeColor)
    
    // The return data in setup is used by Template of the current component
    return {
      themeColor
    }
  },
  components: {
    LevelOne
  }
}
</script>

12. template refs

You can also refer to elements or components on a page through ref().

12.1 Element Reference

The sample code is as follows:

<template>
  <div>
    <h3 ref="h3Ref">TemplateRefOne</h3>
  </div>
</template>

<script>
import { ref, onMounted } from '@vue/composition-api'

export default {
  setup() {
    // Create a DOM reference
    const h3Ref = ref(null)

    // After the DOM is first loaded, a reference to the element can be obtained.
    onMounted(() => {
      // Set font color for dom elements
      // h3Ref.value is a native DOM object
      h3Ref.value.style.color = 'red'
    })

    // return the created reference
    return {
      h3Ref
    }
  }
}
</script>

12.2 Component Reference

The sample code in TemplateRefOne.vue is as follows:

<template>
  <div>
    <h3>TemplateRefOne</h3>
    
    <!-- 4. Click on the button to display the subcomponents count value -->
    <button @click="showNumber">Obtain TemplateRefTwo Medium count value</button>

    <hr />
    <!-- 3. Adding components ref Quote -->
    <TemplateRefTwo ref="comRef" />
  </div>
</template>

<script>
import { ref } from '@vue/composition-api'
import TemplateRefTwo from './TemplateRefTwo'

export default {
  setup() {
    // 1. Create a ref reference for a component
    const comRef = ref(null)

    // 5. Show the count value in the subcomponent
    const showNumber = () => {
      console.log(comRef.value.count)
    }

    // 2. return the references created
    return {
      comRef,
      showNumber
    }
  },
  components: {
    TemplateRefTwo
  }
}
</script>

Sample code in TemplateRefTwo.vue:

<template>
  <div>
    <h5>TemplateRefTwo --- {{count}}</h5>
    <!-- 3. Click on the button to let count Value increment +1 -->
    <button @click="count+=1">+1</button>
  </div>
</template>

<script>
import { ref } from '@vue/composition-api'

export default {
  setup() {
    // 1. Defining responsive data
    const count = ref(0)
    
    // 2. return the responsive data to Template
    return {
      count
    }
  }
}
</script>

13. createComponent

This function is not required unless you want to develop the project in perfect combination with type inference provided by TypeScript.

This function only provides type inference, which facilitates the complete type inference for props in setup() when writing code in combination with TypeScript.

import { createComponent } from 'vue'

export default createComponent({
  props: {
    foo: String
  },
  setup(props) {
    props.foo // <- type: string
  }
})

Keywords: Javascript Vue Attribute github npm

Added by y4m4 on Thu, 10 Oct 2019 14:19:49 +0300