What is a hook
A hook is a function that is used to hook a behavior before it is executed
Let me draw it as a graph
The left is the normal function execution flow, and the right is the execution flow with hook
Before hooks, how did we treat code reuse
Let’s assume a scenario where you are developing a backend management system. In this backend management system, most of them are query forms. Although their business is different, they have certain logical similarities
Common elements: indicates the loading status of data related to pages in the query condition list
These four characteristics are present in almost every form, which means that you need to repeat the logic for each form you write. There are two solutions to this problem in VUe2
- Copy the same logical code every time
- Use Vue mixins for logical commonality
However, there are problems with both approaches
- Copying code is inefficient and, although relatively stable, requires a lot of coding and testing
vue mixins
Logical abstraction can be achieved, but this scheme is too simple and crude scheme, data global sharing, too much usemixin
It will cause the project to go out of control, which is a relatively dangerous scheme
Assume the form page data structure is as follows
{
data: [].// List data
currentPage: 1.// Current page
pageSize: 0.// Number of pages per page
thePageSize: 0.// The number of pages
totalPages: 0./ / the total number of pages
totalSize: 0.// Total number of records
}
Copy the code
In addition to the data returned from the back end, we also need to add some status values to the page to optimize the user experience
status: 'idle' | 'loading' | 'error' | 'success'|...// The current list request status
Copy the code
The above data + state exists in every background form page, which means repeated declarations, repeated docking, and repeated tests
Copying code in a seemingly stable way is actually unstable, because repeated logic is tested every time, and developers tend to be resistant to such tasks because they are tedious and repetitive
There is no very good solution to this problem in VUe2. For this problem, react, from mixin to HOC, and finally to hook, provides a good solution.
Now that @vue/reactivity provides hook capabilities, we can use hooks in Vue to optimize questions
Logic sharing is done through hooks
Following the above scenario, we now assume that we have three background form pages to write
Traditional coding scheme (without hook)
It can be seen that there are many similarities in the three page processes we need to write. In connection with data, although most of the codes are the same, we still need to write repeated tests, such as page number correlation and state correlation logic
Use hooks to perform repetitive logical abstractions
Each call to useHook generates a separate state
Although state and logic depend on the component, useHook can be defined outside of the component in a way that was previously impossible
Although the details of internal logic are different from page to page, the overall process and data structure are the same. Based on this premise, we can abstract for commonality, and then no matter how many pages we use abstract logic, we only need to maintain the abstract logic
Hooks are not exclusive to VUE3
Hook support is added in vue3 version, which does not mean vue3 is bound to hook. In fact, hook functionality provided in Vue3 can be used in any front-end application, namely @vue/reactivity
npm i @vue/reactivity
Copy the code
So vuE3, VUe2, React, and even HTML can use this NPM package
For a concrete implementation of Reactivity, check out my previous article on the reactivity source code
Actual Combat (useReqList)
For ease of understanding, the following code is vue2.x, written in JS
UseReqList is a custom hook that helps us abstract the public logic of the background form. Let’s take a look at the situation when it is not used
Unused useReqList
// ...
data() {
return {
// ...
shopList: []./ / data
homePage: 0.// How much data is on this page
allPage: 0.// How many pages in total
totalSize: 0.// How many entries in total
pageSize: 0.// The maximum number of entries per page
currentPage: 1.// Current page number}},methods: {init() {
this.loading = true
const data = {
currentPage: this.currentPage,
/ /...
}
request(data) / / request
.then((res) = > {
this.shopList = res.data.data
this.currentPage = res.data.currentPage
this.pageSize = res.data.pageSize
this.totalSize = Number(res.data.totalSize)
this.homePage = res.data.thePageSize
this.allPage = res.data.totalPages
})
.finally(() = > {
this.loading = false}})},Copy the code
Using useReqList
import { useReqList } from '@/utils/hook/useReqList'
// ...
data() {
return {
dataList: useReqList()
}
},
methods: {init() {
const data = {
currentPage: this.listData.currentPage || 1./ /...
}
this.listData.run(request(data)) / / request}},// let { data, currentPage, pageSize, thePageSize, totalPages, totalSize, status } = this.listData
Copy the code
As you can see from the above example, after using useReqList
The common variables, the common logic is abstracted away, and the page code is purer
Because of the nature of reactivity, they are all reactive
Avoid repeated coding, repeated testing, save development time
Hook useReqList (Custom Hook useReqList
UseReqList implementation
The internal implementation is the encapsulation of the common logic. The read data is processed by Reactive, and each declaration opens a separate piece of memory for the declarative unit to use because of the closure
import { reactive } from '@vue/reactivity'
/** * Abstraction for the backend form page logic *@returns* /
export function useReqList() {
const defaultState = {
data: [].// Table data
currentPage: 1.// Current page
pageSize: 0.// Number of pages
thePageSize: 0.// The number of current pages
totalPages: 0./ / the total number of pages
totalSize: 0./ / the total number
error: null.// Error cause
status: 'idle'./ / the current state of idle | loading | success | error
}
letstate = reactive({ ... defaultState, })/** * Request successful *@param data* /
const setData = (data) = > {
state.currentPage = data.currentPage
state.pageSize = data.pageSize
state.thePageSize = data.thePageSize
state.totalPages = data.totalPages
state.totalSize = Number(data.totalSize)
state.data = data.data
state.status = 'success'
}
/** * Request failed *@param error* /
const setError = (error) = > {
state.data = []
state.currentPage = 1
state.pageSize = 0
state.thePageSize = 0
state.totalPages = 0
state.totalSize = 0
state.error = error
state.status = 'error'
}
const setLoading = () = > (state.status = 'loading')
const setPage = (num) = > {
state.currentPage = num
}
const setReset = () = > {
state.data = []
state.currentPage = 1
state.pageSize = 0
state.thePageSize = 0
state.totalPages = 0
state.totalSize = 0
state.error = null
state.status = 'idle'
}
const run = (promise) = > {
if(! promise || ! promise.then) {throw new Error('Please pass in data of type Promise')}if (['loading'].includes(state.status)) {
return Promise.reject('Currently in request')
}
setLoading()
return promise
.then((res) = > {
setData(res.data)
})
.catch((err) = > {
console.log(err)
setError(err)
})
.finally(() = >{})}return {
run,
setReset,
setData,
setPage,
setLoading,
setError,
state,
}
}
Copy the code
This package body is basically suitable for most vue2.x developed background management system projects. If you want to use it in the project, you only need to modify the setData part to adapt the back-end data
More vue hook functions
If vuE3 project, you can use hook tool library, VueUse, library provides a large number of common methods, digging the above has the introduction of the tool library article, according to the official website of the library is compatible with VUE2 document
🎩 VueUse works for Vue 2 & 3 within a single package by the power of vue-demi!
Copy the code
There is no test here. If you need it, you can try it
In what usages should a VUE project use hooks
About the Class API and Composition API
The transition from the Class /Option API to the Composition API was painful, and the two apis had very different ways of thinking
For those who have been writing Class and vue2. X for a long time, there are few obvious advantages to vue3 when they first come into contact with vue3. Even if they are not proficient in the setup syntax, they still code according to the thinking of Class and cannot give full play to the advantages of Hook. Class’s ability to organize code in a single file is almost beyond the setup syntax…
Later, the component gained some project experience and learned React Hook again, gradually gaining my own understanding of Hook. Hook is mainly used to separate logic from logic. In React and VUE, Hook can be used to analyze view from view, separate view from logic, and separate logic from logic. In this way, a single responsibility can be realized, and low coupling and high cohesion of logic and view can be achieved on this basis
Hook and Vuex
In a sense, Hook can replace Vuex. The REACT API useContext provides a similar function. However, it is easy for beginners to enter a misunderstanding when they just contact hook. Wrapping variables and logic in a hook and using it in multiple pages creates multiple Spaces in memory that are not shared and are consistent, which is a problem. For vue Hook style global state management libraries, I recommend Pinia
conclusion
After using the Setup syntax for a while, I gradually changed my view from cautious skepticism to embrace hook. The Composition API is good at logical abstraction, type derivation, and many other aspects. Although there are still some minor problems, I believe that you will develop an answer to them in the future. Custom Hook will be more and more popular, embrace Custom Hook,Vue3 bar!
If you encounter any problems in use, please go to QQ group 530496237 and blow water together
You can also add my wechat account: Carpediem-Rollin and join the wechat group