preface
The purpose of this series is to record the problems and solutions encountered in the process of learning vue3 setup syntax sugar.
A, problem,
When I read this article by chance, I felt that useSWR was very nice. The last update to vue-SWR was two years ago, Emmmm.
Second, the implementation
The process is not explained, stepped on a lot of pits, but also because vuE3 is not familiar enough, briefly talk about the attention point.
1. Ref, reative, toRefs
Although ref was only used in the final implementation, I was confused about which one of ref, reative and toRefs should be used together in the implementation process, which made me confused. So let’s talk about the relationship and the difference between them.
- ref
It is used to define a reactive variable. Value is used to obtain the value.
import { ref } from 'vue'
let count = ref(0)
let userInfo = ref({
name:'Joe'.age:18
})
Copy the code
Take a look at the console print
The reactive object created by ref isRefImpl
object
- reative
Reative is usually used to define a responsive array or object. The value can be the same as a normal object or array.
import { reactive } from 'vue'
let userInfo = reactive({
name: 'Joe'.age: 18,})Copy the code
Take a look at the console print
The responsive object created by reative isProxy
object
- toRefs
Converts the reactive object created by Reative to a normal object with the reactive value created by REF
import { toRefs, reactive } from 'vue'
let userInfo = reactive({
name: 'Joe'.age: 18,})let userInfoRefs = toRefs(userInfo)
Copy the code
Take a look at the console print
By modifying theuserInfoRefs
The corresponding property value of userInfo is also changed synchronously
userInfoRefs.age.value = 88
Copy the code
2. Realize the idea and start the body
- Since the setup syntax sugar can only be used in templates at the top level, the setup syntax sugar is first used in the
Setup the top
Defines a reactive expression inlistInfo
. Note:listInfo
Do not point to any other data (including other reactive variables), otherwise it will disconnect from the template’s reactive response.
<script setup>
import { ref } from 'vue'
// Define the top-level variable
let listInfo = ref({
loading: false.data: null.error: null,
})
</script>
<template>
<p>loading:{{ listInfo.loading }}</p>
<p>data:{{ listInfo.data }}</p>
<p>error:{{ listInfo.error }}</p>
</template>
Copy the code
The following page is displayed
- Analog acquisition data
<script setup>
import { ref, onMounted } from 'vue'
import { useRequest } from '@/hooks/request'
// Simulate the interface
let api = (params) = > {
return new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('11111111111')},1000)})}// Get the data method
function fetchData() {
let params = {}
let res = useRequest(api, params)
}
// Get data after the page is mounted
onMounted(() = > {
fetchData()
})
</script>
Copy the code
- It’s going to happen now
useRequest
. Think about it,useRequest
Is aSynchronized methods
How do I asynchronously update data for top-level variables? In fact, as long asuseRequest
Return reactive data and point the top-level variable to the reactive number.
// src/hooks/request.js
import { ref } from 'vue'
export function useRequest(api, params) {
let loading = ref(false)
let error = ref()
let data = ref()
// loading-start
loading.value = true
// Get data
api(params)
/ / success
.then((res) = > {
//set data
data.value = res
// loading-end
loading.value = false
})
/ / fail
.catch((e) = > {
// set error
error.value = e
console.error(e)
// loading-end
loading.value = false
})
return {
loading,
data,
error,
}
}
Copy the code
UseRequest is now implemented to return responsive data, and you just have the top-level variable point to that data.
<script setup>
import { ref, onMounted } from 'vue'
import { useRequest } from '@/hooks/request'
// Define the top-level variable
let listInfo = ref({
loading: false.data: null.error: null,})// Get the data method
function fetchData() {
let params = {}
let res = useRequest(api, params)
// Direct assignment (*)
// listInfo = res
As mentioned earlier, pointing listInfo to any value will result in a responsive break
// Since useRequest returns a plain object made up of reactive variables generated by ref
// Just assign the res value to the corresponding userInfo attribute
Object.assign(listInfo.value, res)
}
</script>
Copy the code
Third, optimize
Because the format of the value obtained by the interface is not always the same as the format rendered by the template, a format conversion function is required.
<script setup>
import { ref, onMounted } from 'vue'
import { useRequest } from '@/hooks/request'
// Get the data method
function fetchData() {
// Data formatting, for example
let fmt = (data) = > {
return 'data' + data
}
let params = {}
let res = useRequest(api, params, fmt)
}
</script>
Copy the code
// src/hooks/request.js
import { ref } from 'vue'
export function useRequest(api, params,fmt) {... api(params)/ / success
.then((res) = > {
//set data
data.value = fmt ? fmt(res) : res
})
...
}
Copy the code
Fourth, integrate
<script setup>
import { ref, onMounted } from 'vue'
import { useRequest } from '@/hooks/request'
// Define the top-level variable
let listInfo = ref({
loading: false.data: null.error: null,})// Simulate the interface
let api = (params) = > {
return new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('11111111111')},1000)})}// Get the data method
function fetchData() {
// Data formatting, for example
let fmt = (data) = > {
return 'data' + data
}
let params = {}
let { loading, data, error } = useRequest(api, params)
Object.assign(listInfo.value,{ loading, data, error })
}
// Get data after the page is mounted
onMounted(() = > {
fetchData()
})
</script>
<template>
<p>loading:{{ listInfo.loading }}</p>
<p>data:{{ listInfo.data }}</p>
<p>error:{{ listInfo.error }}</p>
</template>
Copy the code
// src/hooks/request.js
import { ref } from 'vue'
export function useRequest(api, params, fmt) {
let loading = ref(false)
let error = ref()
let data = ref()
//loading-start
loading.value = true
// Get the previous data
api(params)
/ / success
.then((res) = > {
//set data
data.value = fmt ? fmt(res) : res
//loading-end
loading.value = false
})
/ / fail
.catch((e) = > {
//set error
error.value = e
console.error(e)
//loading-end
loading.value = false
})
return {
loading,
data,
error,
}
}
Copy the code