Skip to content

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

运行效果:
Alt text

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: Alt text

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

运行效果:
Alt text

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

运行效果: Alt text

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

运行效果: Alt text

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('请求出错');
    }
  })

Alt text

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('请求出错');
    }
  })

运行效果:
Alt text 可见设置1S最终发出1次。