Question: What are optional apis and composite apis? ? ?

Composite apis: We can extract the repetitive parts of an interface, along with their functionality, into reusable code pieces. Code sharing and reuse

 

Function: Collects code related to the same logical concern. And that’s exactly what composite apis allow us to do.

In Plain English, you can organize related data, computed method, and watch through setUp for easy reading and understanding

SetUp component options

Features: The new SETUP is executed before component creation

Warning: Try to avoid using this in setup, because setup calls do not get data, method, or computed

The setup method:

Parameters: props, context

Return value: Anything returned can be used in other parts of the component (evaluated properties, methods, lifecycle hooks, and so on) as well as the component’s template

export default { props: { type: String, require: True} setup(props){console.log(props) return props // Anything returned here can be used for the rest of the component}}Copy the code

Practical application:

A component needs a list of repositories and is refreshed whenever the user makes any changes

Import {fetchUserRepositories} from '@/ API/Repositories' // Setup (props){// Define an empty repository array let Repositories = [] const getUserRepositories = async () => {repositories = await FetchUserRepositories (props. User)} return {executables, executables (executables)}Copy the code

Note: At this time the repositories variable is non-reactive

 

Reactive variable with ref

In Vue3 we can use the new ref function to make any reactive variable work anywhere

import { ref } from 'vue'
const counter = ref(0)
Copy the code

Ref takes the parameter and returns it wrapped in an object with value

console.log(counter) // {value: 0}
console.log(counter.value) // 0
counter.value++
console.log(conter.value) // 1
Copy the code

Encapsulating values in an object may seem unnecessary, but it is necessary in order to keep the behavior of different data types consistent in JavaScript. This is because in JavaScript, primitive types such as Number or String are passed by value rather than reference:

 

There is a wrapper object around any value so that we can safely pass it across the application without worrying about losing its responsiveness somewhere.

In other words, ref creates a reactive reference to our value. The concept of references is often used throughout the composite API.

 

Create a reactive Repositoriesvariable using the REF improvement

Import {fetchUserRepositories} from '@/ API/Repositories' import {ref} from 'vue' // Setup (props){// Define an empty repository array let Repositories = ref([]) const getUserRepositories = Async () => { repositories.value = await fetchUserRepositories(props.user) } return { repositories, * * * * * * * * * * * * * * * * * * * * * * * * * *Copy the code

Official example:

// src/components/UserRepositories.vue
import { fetchUserRepositories } from '@/api/repositories'
import { ref } from 'vue'
export default {
  components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
  props: {
    user: {
      type: String,
      required: true
    }
  },
  setup (props) {
    const repositories = ref([])
    const getUserRepositories = async () => {
      repositories.value = await fetchUserRepositories(props.user)
    }
    return {
      repositories,
      getUserRepositories
    }
  },
  data () {
    return {
      filters: { ... }, // 3
      searchQuery: '' // 2
    }
  },
  computed: {
    filteredRepositories () { ... }, // 3
    repositoriesMatchingSearchQuery () { ... }, // 2
  },
  watch: {
    user: 'getUserRepositories' // 1
  },
  methods: {
    updateFilters () { ... }, // 3
  },
  mounted () {
    this.getUserRepositories() // 1
  }
}
Copy the code

We have moved several parts of the first logical concern into the setup method, and they are very close to each other. All that remains is to call getUserRepositories in the Mounted hook and set up a listener to do this should the User Prop change.

 

Register the life function hooks in Setup

This is thanks to several new functions exported by Vue. The lifecycle hooks on the composite API have the same name as the optional API, but are prefixed with ON: Mounted looks like onMounted.

 

// src/components/UserRepositories.vue `setup` function import { fetchUserRepositories } from '@/api/repositories' import { ref, OnMounted} from 'vue' // Setup (props) {const repositories = ref([]) const getUserRepositories = Async () => { Repositories. value = await fetchUserRepositories(props. User)} onMounted(Repositories.getUserRepositories) // `getUserRepositories` return { repositories, getUserRepositories } }Copy the code

 

Watch changes in response

We can use the vUe-imported watch function as well as the watch function called by the component

Three parameters:

  • One is the reactive reference or getter function you want to listen for
  • A callback
  • Optional configuration options
import { ref, watch} from 'vue'
const counter = ref(0)
watch(counter, (newVal, oldVal) => {
  console.log( counter.value )
})
Copy the code

Equivalent to:

export default {
  data() {
    return {
      counter: 0
    }
  },
  watch: {
    counter(newValue, oldValue) {
      console.log(this.counter)
    }
  }
}
Copy the code

Official website example:

// src/components/UserRepositories.vue `setup` function import { fetchUserRepositories } from '@/api/repositories' import { ref, onMounted, watch, ToRefs} from 'vue' // Setup (props) {// Use 'toRefs' to create a responsive reference to prop's' user 'property const {user} = ToRefs (props) Const Repositories = ref([]) const getUserRepositories = Async () => {// Update 'prop.user' to 'user.value' Value = await fetchUserRepositories(user.value)} onMounted(getUserRepositories) // In user Prop Watch (User, getUserRepositories) return {repositories, getUserRepositories}}Copy the code

You may have noticed the use of toRefs at the top of our setup. This is to ensure that our listeners react to changes in user Prop.

 

Independent computed attributes

// src/components/UserRepositories.vue `setup` function import { fetchUserRepositories } from '@/api/repositories' import { ref, onMounted, watch, toRefs, Computed} from 'vue' // In our component setup (props) {// use 'toRefs' to create a responsive reference to' user 'property in props const {user} = ToRefs (props) Const repositories = ref([]) const getUserRepositories = Async () => {// Update 'props. User' to 'user.value' Value = await fetchUserRepositories(user.value)} onMounted(getUserRepositories) // In user Prop Set a listener watch(user, getUserRepositories) const searchQuery = ref('') const repositoriesMatchingSearchQuery = computed(() => { // filter Returns an array, Contains all the elements that accords with a condition return repositories. Value. The filter (repository = > repository. Name. Includes (searchQuery. Value)) return {}) repositories, getUserRepositories, searchQuery, repositoriesMatchingSearchQueryCopy the code

Total: Extraction of logical concerns

The above code makes the setup option very large

This requires that we first extract the above code into a separate composite function before starting any other tasks

 

Start by getting the repository list, useUserRepositories() :

// src/composables/useUserRepositories.js
import { fetchUserRepositories } from '@/api/repositories'
import { ref, onMounted, watch } from 'vue'
export default function useUserRepositories(user) {
  const repositories = ref([])
  const getUserRepositories = async () => {
    repositories.value = await fetchUserRepositories(user.value)
  }
  onMounted(getUserRepositories)
  watch(user, getUserRepositories)
  return {
    repositories,
    getUserRepositories
  }
}
Copy the code

 

And then the search function useRepositoryNameSearch()

// src/composables/useRepositoryNameSearch.js
import { ref, computed } from 'vue'
export default function useRepositoryNameSearch(repositories) {
  const searchQuery = ref('')
  const repositoriesMatchingSearchQuery = computed(() => {
    return repositories.value.filter(repository => {
      return repository.name.includes(searchQuery.value)
    })
  })
  return {
    searchQuery,
    repositoriesMatchingSearchQuery
  }
}
Copy the code

These two are split into separate.js functional modules

 

Now how do you use them in your components

/ / SRC/components/UserRepositories vue / / import warehouse list of function module for js import useUserRepositories the from '@ / composables useUserRepositories / / import search function modules of js import useRepositoryNameSearch the from '@/composables/useRepositoryNameSearch' import { toRefs } from 'vue' export default { components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList }, props: { user: { type: String, required: Setup (props) {const {user} = toRefs(props) And list query method const {repositories, getUserRepositories} = useUserRepositories(user) Pass in the list of repositories returned by the useUserRepositories method // Return the query criteria, and the conditional query method const {searchQuery, Return repositoriesMatchingSearchQuery} = useRepositoryNameSearch (repositories) {/ / because we don't care about unfiltered warehouse / / we can 'Repositories' under the name of exposed filtered repositories: repositoriesMatchingSearchQuery, getUserRepositories, searchQuery, } }, data () { return { filters: { ... }, // 3 } }, computed: { filteredRepositories () { ... }, // 3 }, methods: { updateFilters () { ... }, // 3}}Copy the code