简介
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
})
}
})
}