useRequest函数
useRequest是一个强大的异步数据管理的Hooks,用来简化数据ajax请求后的数据处理。 为了避免跨域问题,可以配置vue.config.js
js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
server: {
port: '9090',
proxy: {
'/mock': {
target: 'http://localhost:8080', // 后端地址
changeOrigin: true,
rewrite: (path) => path.replace(/^\/mock/, '')
}
}
},
css: {
modules: {
localsConvention: 'camelCase'
}
},
})
1. 初步使用useRequest
useRequest默认是在初始化组件的时候自动执行,提供请求数据加载、出错、正常数据三种情况的处理:
jsx
import { useRequest } from 'ahooks'
import axios from 'axios'
import { List, message, App as AppComponent } from 'antd'
const dataUrl = 'https://api.seniverse.com/v3/location/search.json?key=S9TdqSWVKQAmPmXmB&q='
async function getData(inputMsg = '北京') {
const data = await axios.get(dataUrl + inputMsg)
console.log(inputMsg)
return data.data.results
}
function App() {
// 使用ahooks
const { loading, error, data } = useRequest(getData)
// 判断loading和error状态进行直接返回,从而避免执行到下面的List组件进行渲染。
if (loading) {
return <div>Loading...</div>
}
if (error) {
message.info('出错了!')
}
return (
<>
<AppComponent>
<List
size="small"
header={<div>城市列表</div>}
bordered
dataSource={data}
renderItem={(item) => <List.Item key={item.id}>{item.name}</List.Item>}
/>
</AppComponent>
</>
)
}
export default App
运行效果:
2. 手动执行
设置manual
属性为true, 则useRequest不会默认自动执行,需要通过run或者runAsync来触发执行。
jsx
import { useRequest } from 'ahooks'
import axios from 'axios'
import { List, message, App as AppComponent, Input } from 'antd'
const {Search} = Input
const dataUrl = 'http://localhost:9090/mock/queryJson'
async function getData(inputMsg) {
inputMsg = inputMsg?`?name=${inputMsg}`:''
const data = await axios.post(dataUrl + inputMsg)
return data.data
}
function App() {
// 使用ahooks
const { loading, error, run, data } = useRequest(getData, {
manual: true
})
const handleSearch = (inputMsg) => {
run(inputMsg)
}
if (loading) {
return <div>Loading...</div>
}
if (error) {
message.info('出错了!')
}
return (
<>
<AppComponent>
<Search placeholder="名称查询" enterButton="搜索" loading={loading} onSearch={handleSearch}/>
<List
size="small"
header={<div>信息列表</div>}
bordered
dataSource={data}
renderItem={(item) => <List.Item key={item.id}>{item.name}</List.Item>}
/>
</AppComponent>
</>
)
}
export default App
运行的时候,设置网络速度为3G:
3. 生命周期钩子
useRequest 提供了以下几个生命周期配置项,供你在异步函数的不同阶段做一些处理。
onBefore
:请求之前触发onSuccess
:请求成功触发onError
:请求失败触发onFinally
:请求完成触发
上面的代码可以优化,不用判断loading和error状态值, 同时可以使用上搜索框自带的加载样式:
jsx
import { useRequest } from 'ahooks'
import axios from 'axios'
import { List, message, App as AppComponent, FloatButton, Input } from 'antd'
import { useState } from 'react'
const {Search} = Input
const dataUrl = 'http://localhost:9090/mock/queryJson'
async function getData(inputMsg) {
inputMsg = inputMsg?`?name=${inputMsg}`:''
const data = await axios.post(dataUrl + inputMsg)
return data.data
}
function App() {
const [listData, setListData] = useState([])
// 使用ahooks
const { loading, run } = useRequest(getData, {
manual: true,
onBefore: (params) => {
console.log('开始请求后端。。。')
},
onSuccess: (result, params) => {
// 设置列表数据,交给react渲染
setListData(result)
},
onError: (error) => {
message.error('请求出错');
},
onFinally: (params, result, error) => {
console.log('请求完成!')
}
})
const handleSearch = (inputMsg) => {
run(inputMsg)
}
return (
<>
<AppComponent>
<Search placeholder="名称搜索" enterButton="搜索" loading={loading} onSearch={handleSearch}/>
<List
size="small"
header={<div>信息列表</div>}
bordered
dataSource={listData}
renderItem={(item) => <List.Item key={item.id}>{item.name}</List.Item>}
/>
</AppComponent>
</>
)
}
export default App
运行效果:
3. 使用刷新特性
useRequest提供了refresh和refreshAsync方法,使我们可以使用上一次的参数,重新发起请求。
jsx
import { useRequest } from 'ahooks'
import axios from 'axios'
import { List, message, App as AppComponent, FloatButton, Input } from 'antd'
import { useState } from 'react'
import { ReloadOutlined } from '@ant-design/icons'
const {Search} = Input
const dataUrl = 'http://localhost:9090/mock/queryJson'
async function getData(inputMsg) {
inputMsg = inputMsg?`?name=${inputMsg}`:''
const data = await axios.post(dataUrl + inputMsg)
return data.data
}
function App() {
const [listData, setListData] = useState([])
// 使用ahooks
const { loading, run, refresh } = useRequest(getData, {
manual: true,
onSuccess: (result, params) => {
// 设置列表数据,交给react渲染
setListData(result)
},
onError: (error) => {
message.error('请求出错');
}
})
const handleSearch = (inputMsg) => {
run(inputMsg)
}
const handleRefresh = () => {
refresh()
}
return (
<>
<AppComponent>
<Search placeholder="名称搜索" enterButton="搜索" loading={loading} onSearch={handleSearch}/>
<FloatButton onClick={handleRefresh} icon={<ReloadOutlined/>}></FloatButton>
<List
size="small"
header={<div>信息列表</div>}
bordered
dataSource={listData}
renderItem={(item) => <List.Item key={item.id}>{item.name}</List.Item>}
/>
</AppComponent>
</>
)
}
export default App
运行效果:
4. 结合自动和手动
jsx
import { useRequest } from 'ahooks'
import axios from 'axios'
import { List, message, App as AppComponent, FloatButton, Input } from 'antd'
import { useState } from 'react'
import { ReloadOutlined } from '@ant-design/icons'
const {Search} = Input
const dataApiUrl = 'http://localhost:9090/mock/queryJson'
async function getData(inputMsg) {
inputMsg = inputMsg?`?name=${inputMsg}`:''
const data = await axios.post(dataApiUrl + inputMsg)
return data.data
}
function App() {
const [listData, setListData] = useState([])
const { loading, run, refresh } = useRequest(getData, {
onSuccess: (result, params) => {
// 设置列表数据,交给react渲染
setListData(result)
},
onError: (error) => {
console.log(error)
message.error('请求出错');
}
})
const handleSearch = (inputMsg) => {
run(inputMsg)
}
const handleRefresh = () => {
refresh()
}
return (
<>
<AppComponent>
<Search placeholder="名称搜索" enterButton="搜索" loading={loading} onSearch={handleSearch}/>
<FloatButton onClick={handleRefresh} icon={<ReloadOutlined/>}></FloatButton>
<List
size="small"
header={<div>信息列表</div>}
bordered
dataSource={listData}
renderItem={(item) => <List.Item key={item.id}>{item.name}</List.Item>}
/>
</AppComponent>
</>
)
}
export default App
运行效果:
5. 请求参数管理
useRequest会记录当次调用请求的参数数组params。如果是自动执行的话(manul:false), 可以设置首次请求参数defaultParams:
jsx
import { useRequest } from 'ahooks'
import axios from 'axios'
import { List, message, App as AppComponent, Input } from 'antd'
import { useState } from 'react'
const {Search} = Input
const dataUrl = 'http://localhost:9090/mock/queryJson'
async function getData(inputMsg) {
inputMsg = inputMsg?`?name=${inputMsg}`:''
const data = await axios.post(dataUrl + inputMsg)
return data.data
}
function App() {
const [listData, setListData] = useState([])
const { loading, run, params } = useRequest(getData, {
defaultParams:'', // 设置默认参数
onSuccess: (result, queryParams) => {
// 设置列表数据,交给react渲染
setListData(result)
// 可以看到params和queryParams是同一个对象
console.log(params===queryParams)
},
onError: (error) => {
console.log(error)
message.error('请求出错');
}
})
const handleSearch = (inputMsg) => {
run(inputMsg)
}
return (
<>
<AppComponent>
<Search placeholder="名称搜索" enterButton="搜索" loading={loading} onSearch={handleSearch}/>
<List
size="small"
header={<div>信息列表</div>}
bordered
dataSource={listData}
renderItem={(item) => <List.Item key={item.id}>{item.name}</List.Item>}
/>
</AppComponent>
</>
)
}
export default App
5. 使用轮询
设置pollingInterval可以定时触发执行:
jsx
const { data, run, cancel } = useRequest(getUsername, {
pollingInterval: 3000,
});
表示每隔3秒请求一次
6. 屏幕聚焦重新请求
设置refreshOnWindowFocus可以在浏览器窗口refocus和revisible时会重新发起请求。
jsx
const { loading, run, params } = useRequest(getData, {
defaultParams:'', // 设置默认参数
refreshOnWindowFocus: true, // 重新聚焦发起请求
onSuccess: (result, queryParams) => {
// 设置列表数据,交给react渲染
setListData(result)
// 可以看到params和queryParams是同一个对象
console.log(params===queryParams)
},
onError: (error) => {
console.log(error)
message.error('请求出错');
}
})
6. 使用防抖节流特性
指定时间范围内最后一次发出请求就是防抖,而节流是直接限制请求的时间点分布执行。他们都是减少函数的执行不必要次数的方式。
jsx
const { loading, run, params } = useRequest(getData, {
defaultParams:'', // 设置默认参数
debounceWait: 1000, // 设置1S范围内只算一次请求
refreshOnWindowFocus: true, // 重新聚焦发起请求
onSuccess: (result, queryParams) => {
// 设置列表数据,交给react渲染
setListData(result)
// 可以看到params和queryParams是同一个对象
console.log(params===queryParams)
},
onError: (error) => {
console.log(error)
message.error('请求出错');
}
})
运行效果: 可见设置1S最终发出1次。