http请求那些事 a year ago
对象初始化
来看一个demo:
如果我们运行代码,大概率是会出错的,因为IDE已经标红了 😁
果不其然,出错了 无法读取属性title
作为一个合格的coder,就算IDE不给提示我们也要知道为什么。
这与react生命周期相关
组件在render下面这段html代码时,useEffect()
(相当于上图的componentDidMount()
)还未执行,此时的post为null
<>
<h3>{post.title}</h3>
<div>{post.body}</div>
</>
null下面是没有title属性的,所以报错
那么如何fix这个bug呢?对象后面加个?
即可
来看看完整的demo:
import { memo, useEffect, useState } from 'react'
type Post = {
title: string;
body: string;
}
const App = memo(() => {
const [post, setPost] = useState<Post | null>(null)
useEffect(() => {
fetch('https://dummyjson.com/posts/1')
.then(res => res.json())
.then(data => setPost(data));
}, [])
return (
<>
<h3>{post?.title}</h3>
<div>{post?.body}</div>
</>
)
})
export default App
接下来加点需求,给demo添加一个loading效果
import { memo, useEffect, useState } from 'react'
type Post = {
title: string;
body: string;
}
const App = memo(() => {
const [post, setPost] = useState<Post | null>(null)
const [loading, setloading] = useState<boolean>(true)
useEffect(() => {
fetch('https://dummyjson.com/posts/1')
.then(res => res.json())
.then(data => {
setPost(data);
setloading(false)
})
}, [])
return (
<>
{
loading ? <div>loading...</div> : (<>
<h3>{post?.title}</h3>
<div>{post?.body}</div>
</>)
}
</>
)
})
export default App
继续改变需求,通过点击按钮随机获取post
import { memo, useEffect, useState } from 'react'
type Post = {
title: string;
body: string;
}
const App = memo(() => {
const [id, setId] = useState<number>(1)
return <>
<button onClick={() => setId(Math.floor(Math.random() * 100))}>随机获取post</button>
<DisplayPost id={id} />
</>
})
export default App
const DisplayPost = memo(({ id }: { id: number }) => {
const [post, setPost] = useState<Post | null>(null)
const [loading, setloading] = useState<boolean>(true)
useEffect(() => {
fetch(`https://dummyjson.com/posts/${id}`)
.then(res => res.json())
.then(data => {
setPost(data);
setloading(false)
})
}, [id])
return (
<>
{
loading ? <div>loading...</div> : (<>
<h3>{post?.title}</h3>
<div>{post?.body}</div>
</>)
}
</>
)
})
上述demo已经满足了我们的需求,但是有个潜在的隐患
如果某一时刻有大量狂点狂人在那click,那么势必会“连累”服务器,所以我们需要在客户端作一些限流处理
让浏览器主动丢弃一些请求
添加AbortController,对客户端限流,减轻服务端压力
关于AbortController的使用, 可以参考这篇博客
import { memo, useEffect, useState } from 'react'
type Post = {
title: string;
body: string;
}
const App = memo(() => {
const [id, setId] = useState<number>(1)
return <>
<button onClick={() => setId(Math.floor(Math.random() * 100))}>随机获取post</button>
<DisplayPost id={id} />
</>
})
export default App
const DisplayPost = memo(({ id }: { id: number }) => {
const [post, setPost] = useState<Post | null>(null)
const [loading, setloading] = useState<boolean>(true)
useEffect(() => {
const controller = new AbortController()
fetch(`https://dummyjson.com/posts/${id}`, {
signal: controller.signal
})
.then(res => res.json())
.then(data => {
setPost(data);
setloading(false)
})
return () => {
controller.abort()
}
}, [id])
return (
<>
{
loading ? <div>loading...</div> : (<>
<h3>{post?.title}</h3>
<div>{post?.body}</div>
</>)
}
</>
)
})
我们再来狂点试试
错误处理
import { memo, useEffect, useState } from 'react'
type Post = {
title: string;
body: string;
}
const App = memo(() => {
const [id, setId] = useState<number>(1)
return <>
<button onClick={() => setId(Math.floor(Math.random() * 100))}>随机获取post</button>
<DisplayPost id={id} />
</>
})
export default App
const DisplayPost = memo(({ id }: { id: number }) => {
const [post, setPost] = useState<Post | null>(null)
const [loading, setloading] = useState<boolean>(true)
const [err, setErr] = useState(null)
useEffect(() => {
const controller = new AbortController()
fetch(`https://dummyjson.com/posts1/${id}`, {
signal: controller.signal
}).then(
res => {
if (!res.ok) {
throw Error("failed to fetch the data from the resource")
}
return res.json()
}
)
.then(data => {
setPost(data);
setloading(false)
setErr(null)
}).catch(err => {
setloading(false)
setErr(err?.message)
}
)
return () => {
controller.abort()
}
}, [id])
return (
<>
{err && <div>{err}</div>}
{
loading ? <div>loading...</div> : (<>
<h3>{post?.title}</h3>
<div>{post?.body}</div>
</>)
}
</>
)
})
- 上一篇: goland active
- 下一篇: react:自定义hook