useRequest 使用实践

简介

1 .一个http请求往往包含着很多的状态,有时还需要用reducer来整理状态,突然想到还有这个,顺便学习下这个
2 .之前也有用过,但是失败了,一直没有请求成功.这次就用fetch,不用axios,少引入一个库试下
3 .

为什么这样两个不行了

 const {loading,run}=useRequest((data)=>({
        // 这里的data应该是run传进来的
        url:"http://127.0.0.1:8080/insert",
        method:"post",
        body:JSON.stringify(data),
        headers:{
            'Content-Type': 'application/json;charset=utf-8'
        }

    }),{
        manual:true,
        onSuccess:(result)=>{
            console.log(result)
            if(result.status==='ok'){
                message.success('流程已经提交')
            }
        }
    })

    const {finLoading,runFind}=useRequest((data)=>({
        url:"http://127.0.0.1:8080/find_one",
        method:"post",
        body:JSON.stringify(data),
        headers:{
            'Content-Type': 'application/json;charset=utf-8'
        }
    }),{
        manual:true,
        onSuccess:(result)=>{
            console.log(result)
        }
        }
    )
//这种多个的时候第二个就不能用解构分离了,要这样
const {loading,run}=useRequest((data)=>({
        // 这里的data应该是run传进来的
        url:"http://127.0.0.1:8080/insert",
        method:"post",
        body:JSON.stringify(data),
        headers:{
            'Content-Type': 'application/json;charset=utf-8'
        }

    }),{
        manual:true,
        onSuccess:(result)=>{
            console.log(result)
            if(result.status==='ok'){
                message.success('流程已经提交')
            }
        }
    })

    const request2=useRequest((data)=>({
        url:"http://127.0.0.1:8080/find_one",
        method:"post",
        body:JSON.stringify(data),
        headers:{
            'Content-Type': 'application/json;charset=utf-8'
        }
    }),{
        manual:true,
        onSuccess:(result)=>{
            console.log(result)
            handleInsert(result.data)
        }
        }
    )

//第二个所有的变量都要挂载在request2这个返回值上,包括那些方法

轮询实现

1 .之前的实现,很繁琐

useInterval(
      ()=>{
          if(fightOver===fightCount){
            setInterval(null)
            return
          }
          handleFight()
          setFightOver(fightOver+1)
      },
      interval,
      {immediate:false}
    )
//开一个useInterval,里面调用战斗函数
//结束条件是另一个值,每次调用一下这个函数,另一个值+1,如果大于等于,就不调用

2 .新版

import {React,useState,useEffect}from 'react'
import { useRequest } from 'ahooks'
// 轮询测试


export default function Test(props){
    let [count,setCount]=useState(0)

    const {data,loading,run,cancel}=useRequest(()=>({
        url:"http://127.0.0.1:8080/test"
    }),
    // get请求例子
    {
        pollingInterval:1000,
        pollingWhenHidden:false,
        // 当前界面不在窗口的时候是否自动
        // manual:true,
        // 第一次调用必须手动
        onSuccess:(data)=>{
            setCount(x=>x+1)
            console.log(data)
        }
    })

    // 关掉循环的操作,还是需要单独写,只不过更加独立出来了,但是另一个就是还没有加成到里面
    useEffect(()=>{
        if(count>=10){
            cancel()
            console.log('取消请求',count)
        }
    },[count])

    return (
        <div className="header">
            测试
            <button onClick={cancel}>停止</button>
            <button onClick={run}>开始</button>
        </div>
    )
}

自动管理的状态

1 .data:请求返回的数据
2 .run:执行请求,会自动捕获异常,通过下面配置的onError函数获取异常报错
3 .runAsync:是一个返回Promise的异步函数,使用这个调用的话,需要自己捕获异常

runAsync().then((data)=>{}).catch((error)=>{})

4 .refresh:再次用刚才的参数请求.如果参数比较复杂的话,这个非常有用,不用你在算了

配置

1 .manual:true.是否自动请求
2 .生命周期:为什么只有onSuccess,onError可以有效

//请求之前触发
onBefore: (params) => {
          message.info(`Start Request: ${params[0]}`);
        },
//请求成功触发
onSuccess: (result, params) => {
          message.success(`The username was changed to "${params[0]}" !`);
        },
//请求错误触发
onError: (error) => {
          message.error(error.message);
        },
//请求结束触发
onFinally: (params, result, error) => {
          message.info(`Request finish`);
        },

3 .loadingDelay:300:如果300秒内请求返回,则不出现loading状态.如果很快返回的话,会有闪烁.

1 .loadingDealy支持动态变化

取消请求

1 .主动请求 cancel()函数
2 .被动请求

1 .组件卸载的时候,取消正在进行的请求
2 .竞态取消,当上一次请求还没有返回时,又发起下一次请求,则会取消上一次的请求

依赖请求

1 .这个可以写在里面,不像轮询停止的条件,那个是不行的.

const [userId, setUserId] = useState('1');

const { data, run } = useRequest(() => getUserSchool(userId), {
  refreshDeps: [userId],
});

2 .等于这个

const [userId, setUserId] = useState('1');

const { data, refresh } = useRequest(() => getUserSchool(userId));

useEffect(() => {
  refresh();
}, [userId]);

屏幕聚焦重新请求

1 .浏览器窗口refocus,revisible时,会重新发起请求

{
        // manual: true,
        //必须保证这个是false

        loadingDelay:1000,
        onSuccess:(data)=>{
            console.log(data)
        },
        refreshOnWindowFocus:true,
         focusTimespan:1000
        //重新请求间隔,单位是毫秒
    })

2 .原理就是检测了浏览器的visibilityChange,focus事件

防抖:最后一次触发计算时间,2.10.12.这个版本不行,需要升到"ahooks": "3.0.0"

1 .添加防抖模式,频繁触发run,runAsync.会进行防抖策略请求.XX时间内再次触发这个函数,就以xx时间的算最终触发
2 .备注

1 .runAsync只有真正执行的时候,才会返回Promise,没有执行时,不会有任何返回
2 .cancel可以中止正在等待执行的函数

3 .相关参数

1 .debounceWait:防抖等待时间
2 .debounceMaxWait:允许被延迟的最大值
3 .debounceLeading:在延迟开始前执行调用
4 .debounceTrailing:在延迟结束后执行调用

4 .事件之后再最后一次触发的300秒后执行
5 .一般都是输入,查询.因为输入一直再触发,所以要等输入完毕之后在做操作
6 .果然还是需要3.0才可以,不然没效果

 async function get(){
        return fetch('http://127.0.0.1:8080/test')
    }
    
    const {data,loading,run,refresh,cancel}=useRequest(get,
    {
        onSuccess:(data)=>{
            console.log(data)
        },
        debounceWait: 500,
        manual:true,
        debounceMaxWait:1000,
    })

    return (
        <div className="header">
            测试{loading?"loading":"请求完毕"}
            <button onClick={cancel}>停止</button>
            <button onClick={run}>开始</button>
            <button onClick={refresh}>重新</button>
            <input onChange={run}/>
        </div>
    )

节流:第一次触发就计算时间,只有超过了时间才能执行下一次

1 .第一次触发了300秒后才会执行下一个函数
2 .在这个时间内多次触发,时间结束只会在触发一次
3 .cancel可以在中止正在等待执行的函数

async function get(){
        return fetch('http://127.0.0.1:8080/test')
    }

    const {data,loading,run,refresh,cancel}=useRequest(get,
    {
        onSuccess:(data)=>{
            console.log(data)
        },
        manual:true,
        throttleWait:10000,
    })

    return (
        <div className="header">
            测试{loading?"loading":"请求完毕"}
            <button onClick={cancel}>停止</button>
            <button onClick={run}>开始</button>
            <button onClick={refresh}>重新</button>
            <input onChange={run}/>
        </div>
    )

缓存&SWR

1 .如果设置了options.cacheKey,useRequest会将当前请求成功的数据缓存起来.下次组件初始话时,如果有缓存数据,我们会优先返回缓存数据,然后在背后发送新请求
2 .staleTime:设置数据保持新鲜时间,在时间内,我们认为数据时新鲜的,不会重新发送请求.如果设置为-1,则表示数据永远新鲜
3 .cacheTime:设置数据缓存时间,超过这个时间,会清空这条数据缓存.缓存的回收时间,默认5分钟后回收,如果设置为-1,表示缓存数据永远不会过期
4 .他这个是先使用旧的,如果有新的数据,就会拿新的替换
5 .数据共享

1 .同一个cacheKey的内容,在全局是共享的.请求的promise共享,相同的cacheKey同时只会有一个在发起请求
2 .数据同步,任何时候当我们改变其中某个cacheKey的内容时,其他相同cacheKey的内容均会同步
3 .缓存的数据包括data,params,我们可以记忆上一次请求的条件,并在下次初始化
4 .只有成功的请求数据才会缓存
5 .
import {React,useState,useEffect}from 'react'
import { useRequest,clearCache } from 'ahooks'
import {message} from 'antd'
// 轮询测试


export default function Test(props){
    async function get(){
        return fetch('http://127.0.0.1:8080/test')
    }

    const {data,loading,run,refresh,cancel}=useRequest(get,
    {
        onSuccess:(data)=>{
            console.log(data)
        },
        cacheKey:'cacheKey-demo',
        staleTime:10000,
    })

    return (
        <div className="header">
            测试{loading?"loading":"请求完毕"}
            <button onClick={()=>clearCache('cacheKey-demo')}>停止</button>
            <button onClick={run}>开始</button>
            <button onClick={refresh}>重新</button>
            <input onChange={run}/>

        </div>
    )
}

错误重试

1 .指定重试次数,会在失败后进行重试
2 .可以跑通的例子

async function get(){
        return new Promise((resolve,reject)=>{
            fetch('http://127.0.0.1:8080/test')
            .then((e)=>{
                // resolve(e)
                if(e.ok){
                    return e.json()
                }else{
                    reject('something')
                }
            })
            .then((e)=>{
                resolve(e)
            })
            .catch((e)=>{
                console.logh(e,'error')
                reject(new Error('fail to get'))
            })
            // 这种检测还是不行
        })
    }

  const {data,loading,run,refresh,cancel,error}=useRequest(get,
    {
        onSuccess:(data)=>{
            console.log(data,error)
        },
        retryCount:5,
        onError:(data)=>{
            console.log('请求错误',data,error)
        }
    })


//检测不到的写法
 async function get1(){
        let url = 'http://127.0.0.1:8080/test1';
        try {
            let response = await fetch(url);
            return await response.json();
        } catch (error) {
            console.log('Request Failed', error);
        }
    }

更全的fetch错误检测

fetch('http://127.0.0.1:8080/test1')
        .then(handleResponse)
        .then(data=>console.log(data))
        .then(error=>console.log(error))


        function handleResponse(response){
            let contentType=response.headers.get('content-type')
            console.log(contentType)
            if(contentType.includes('application/json')){
                return handleJSONResponse(response)
            }else if(contentType.includes('text/html')){
                return handleTextResponse(response)
            }else{
                throw new Error(`Sorry,content-type ${contentType} not supported`)
            }

        }

        function handleJSONResponse(response){
            return response.json()
            .then(json=>{
                if(response.ok){
                    return json
                }else{
                    return Promise.reject(Object.assign({},json,{
                        status:response.status,
                        statusText:response.statusText,
                    }))
                }
            })
        }

        function handleTextResponse(response){
            return response.text()
            .then(text=>{
                if(response.ok){
                    return text
                }else{
                    return Promise.reject({
                        status:response.status,
                        statusText:response.statusText,
                        err:text
                    })
                }        
            })
        }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容