我们将 state 从照应对象改为一个普通对象,然后一切属性都运用 ref 包裹,这样修正后,后续的解构才做才能失效。这样的弊端就是,state 的每个属性在修正时,都必须取其value 属性。但是在模板中不需求追加 .value,Vue 3 外部有对其停止处置。
import { ref, onMounted, watchEffect } from 'vue'
export default {
setup() {
const state = {
input: ref('vue'),
query: ref('vue'),
hits: ref([])
}
const fetchData = async (query) => {
const data = await fetch(
`https://hn.algolia.com/api/v1/search?query=${query}`
).then(rsp => rsp.json())
state.hits.value = data.hits
}
onMounted(() => {
watchEffect(() => {
fetchData(state.query.value)
})
})
const setQuery = () => {
state.query.value = state.input.value
}
return {
...state,
setQuery,
}
}
}
有没有办法保持 state 为照应对象,同时又支持其对象解构的呢?当然是有的,Vue 3 也提供了处置方案:toRefs() 。toRefs() 办法可以将一个照应对象变为普通对象,并且给每个属性加上 ref()。
import { toRefs, reactive, onMounted, watchEffect } from 'vue'
export default {
setup() {
const state = reactive({
input: 'vue',
query: 'vue',
hits: []
})
const fetchData = async (query) => {
const data = await fetch(
`https://hn.algolia.com/api/v1/search?query=${query}`
).then(rsp => rsp.json())
state.hits = data.hits
}
onMounted(() => {
watchEffect(() => {
fetchData(state.query)
})
})
const setQuery = () => {
state.query = state.input
}
return {
...toRefs(state),
setQuery,
}
}
}
Loading 与 Error 形状
通常,我们发起央求的时分,需求为央求添加 Loading 和 Error 形状,我们只需求在 state中添加两个变量来控制这两种形状即可。
export default {
setup() {
const state = reactive({
input: 'vue',
query: 'vue',
hits: [],
error: false,
loading: false,
})
const fetchData = async (query) => {
state.error = false
state.loading = true
try {
const data = await fetch(
`https://hn.algolia.com/api/v1/search?query=${query}`
).then(rsp => rsp.json())
state.hits = data.hits
} catch {
state.error = true
}
state.loading = false
}
onMounted(() => {
watchEffect(() => {
fetchData(state.query)
})
})
const setQuery = () => {
state.query = state.input
}
return {
...toRefs(state),
setQuery,
}
}
}
同时在模板运用这两个变量:
<template>
<input type="text" v-model="input" />
<button @click="setQuery">搜索</button>
<div v-if="loading">Loading ...</div>
<div v-else-if="error">Something went wrong ...</div>
<ul v-else>
<li
v-for="item of hits"
:key="item.objectID"
>
<a :href="item.url">{{item.title}}</a>
</li>
</ul>
</template>
展现 Loading、Error 形状:
Demo
将数据央求逻辑笼统
用过 umi 的同窗一定知道 umi 提供了一个叫做 useRequest 的 Hooks,用于央求数据十分的方便,那么我们经过 Vue 的组合 API 也可以笼统出一个相似于 useRequest 的公共办法。
接上去我们新建一个文件 useRequest.js :
import {
toRefs,
reactive,
} from 'vue'
export default (options) => {
const { url } = options
const state = reactive({
data: {},
error: false,
loading: false,
})
const run = async () => {
state.error = false
state.loading = true
try {
const result = await fetch(url).then(res => res.json())
state.data = result
} catch(e) {
state.error = true
}
state.loading = false
}
return {
run,
...toRefs(state)
}
}
然后在 App.vue 中引入:
<template>
<input type="text" v-model="query" />
<button @click="search">搜索</button>
<div v-if="loading">Loading ...</div>
<div v-else-if="error">Something went wrong ...</div>
<ul v-else>
<li
v-for="item of data.hits"
:key="item.objectID"
>
<a :href="item.url">{{item.title}}</a>
</li>
</ul>
</template>
<script>
import { ref, onMounted } from 'vue'
import useRequest from './useRequest'
export default {
setup() {
const query = ref('vue')
const { data, loading, error, run } = useRequest({
url: 'https://hn.algolia.com/api/v1/search'
})
onMounted(() => {
run()
})
return {
data,
query,
error,
loading,
search: run,
}
}
}
</script>
以后的 useRequest 还有两个缺陷:
1.传入的 url 是固定的,query 修正后,不能及时的反响到 url 上;
2.不能自动央求,需求手动调用一下 run 办法;
import {
isRef,
toRefs,
reactive,
onMounted,
} from 'vue'
export default (options) => {
const { url, manual = false, params = {} } = options
const state = reactive({
data: {},
error: false,
loading: false,
})
const run = async () => {
// 拼接查询参数
let query = ''
Object.keys(params).forEach(key => {
const val = params[key]
// 假设去 ref 对象,需求取 .value 属性
const value = isRef(val) ? val.value : val
query += `${key}=${value}&`
})
state.error = false
state.loading = true
try {
const result = await fetch(`${url}?${query}`)
.then(res => res.json())
state.data = result
} catch(e) {
state.error = true
}
state.loading = false
}
onMounted(() => {
// 第一次能否需求手动调用
!manual && run()
})
return {
run,
...toRefs(state)
}
}
经过修正后,我们的逻辑就变得异常复杂了。
import useRequest from './useRequest'
export default {
setup() {
const query = ref('vue')
const { data, loading, error, run } = useRequest(
{
url: 'https://hn.algolia.com/api/v1/search',
params: {
query
}
}
)
return {
data,
query,
error,
loading,
search: run,
}
}
}
当然,这个 useRequest 还有很多可以完善的中央,例如:不支持 http 办法修正、不支持节流防抖、不支持超时时间等等。最后,希望大家看完文章后能有所播种。
本文转载自微信群众号「更了不起的前端」,可以经过以下二维码关注。转载本文请联络更了不起的前端群众号。
【编辑引荐】
重新思索可继续数据中心设计
Vue中Axios的封装和API接口的管理
「算法与数据结构」带你看分治算法之美
物联网数据智能:打造“及时照应”企业
SocialBlock:可以改善智慧城市中数据安全的技术
(责任编辑:admin)