使用 React Hooks 在不同页面中获取请求
Posted
技术标签:
【中文标题】使用 React Hooks 在不同页面中获取请求【英文标题】:Fetch Requests in different pages with React Hooks 【发布时间】:2020-02-10 12:20:15 【问题描述】:我正在使用 React Hooks 构建一个网站,我有两个不同的页面(Workshops.js 和 Shows.js)从同一个 API 获取数据,只是使用不同的参数(?type=0 和 ?type=1 )。 获取数据后,我将映射结果(那里有一个可重用的组件会很好......请参阅下面代码中的 cmets)。当用户点击节目或研讨会时,他将被重定向到同一页面。
现在代码可以正常工作了。 有没有更优雅的方法来避免重复相同的代码? ...类似于 Angular 中的服务?
谢谢!
这里是 Workshop.js。
import React, useState, useEffect from 'react';
import Link from 'react-router-dom'
import api from '../../maps/Api'
const Workshops = () =>
const [ workshops, setWorkshop ] = useState([])
const [ isLoading, setIsLoading ] = useState(false)
const [ error, setError ] = useState(null)
const GET_URL = api.get.workshops /* http://someapi/workshops?type=0 */
useEffect(() =>
setIsLoading(true)
fetch(GET_URL, headers:
"Accept": "application/json",
"Access-Control-Allow-Origin": "*"
)
.then(res =>
return (res.ok) ? res.json() : new Error("Mistake!")
)
.then(workshops =>
if(workshops.upcoming)
setWorkshop(workshops.upcoming);
setIsLoading(false);
)
.catch(error =>
setError(error)
)
, [GET_URL])
if ( error ) return <p> error.message </p>
if ( isLoading )
return <p>Loading workshops...</p>
return(
<main>
<div className='content'>
<div className='contentCol'>
<ul id='workshopBox'>
workshops.map( (workshop, i) => (
<li> // FROM HERE...
<div
className='workshop-active'>
<h2> workshop.title </h2>
<p> workshop.description </p>
<p> workshop.place </p>
<p> (new Date(workshop.date).toLocaleDateString("it-IT",
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
))</p>
<p> (new Date(workshop.date).toLocaleTimeString("it-IT",
hour: '2-digit',
minute: '2-digit',
hour12: true
))</p>
<p> Full price workshop.price_full + ', 00' € </p>
<p> Early bird price workshop.price_earlybirds + ', 00' € </p>
<p>
<Link to=`/workshops/$ workshop.id`>
<button>Details</button>
</Link>
</p>
<br/>
</div>
</li> //..to HERE I WOULD LIKE TO USE A REUSABLE COMPONENT
))
</ul>
</div>
</div>
</main>
)
export default Workshops
这里是 Shows.js
import React, useState, useEffect from 'react';
//import Link from 'react-router-dom'
import api from '../maps/Api'
const Spettacoli = () =>
const [ shows, setShows ] = useState([])
const [ isLoading, setIsLoading ] = useState(false)
const [ error, setError ] = useState(null)
const GET_URL = api.get.shows /* http://someapi/workshops?type=1 */
useEffect(() =>
setIsLoading(true)
fetch(GET_URL, headers:
"Accept": "application/json",
"Access-Control-Allow-Origin": "*"
)
.then(res =>
return (res.ok) ? res.json() : new Error("Mistake!")
)
.then(shows =>
setShows(shows)
setIsLoading(false)
)
.catch(error =>
setError(error)
)
, [GET_URL])
return(
<main>
<div className='content'>
<div className='contentCol'>
/* SAME INTERFACE AS WORKSHOP */
</div>
</div>
</main>
)
export default Shows
【问题讨论】:
节目的界面和工作坊完全一样吗? 是的!刚刚编辑了我的帖子。 只需将类型作为道具传递给您的组件并使用道具值设置您的api。 【参考方案1】:所以你可以创建你的custom hook:
function useMyDataFetch(GET_URL)
const [ data, setData ] = useState([])
const [ isLoading, setIsLoading ] = useState(true)
const [ error, setError ] = useState(null)
useEffect(() =>
let hasBeenAborted = false; // added
setIsLoading(true)
fetch(GET_URL, headers:
"Accept": "application/json",
"Access-Control-Allow-Origin": "*"
)
.then(res =>
return (res.ok) ? res.json() : new Error("Mistake!")
)
.then(data =>
if (hasBeenAborted) return; // added
if(data.upcoming)
setData(data.upcoming);
setIsLoading(false);
)
.catch(error =>
if (hasBeenAborted) return; // added
setIsLoading(false); // added
setError(error)
);
return () => hasBeenAborted = true; // added
, [GET_URL]);
return data, error, isLoading ;
并在您的组件中使用它。
我用// added
标记的注意线。
hasBeenAborted
允许我们在 GET_URL
因任何原因对同一组件进行更新时做出反应。 Cleanup in useEffect
非常重要,因此我们避免了竞争条件。
我们可以使用AbortController
代替hasBeenAborted
标志,但这样我们仍然会落入catch
分支,并且需要额外的if
来区分请求是否已被取消或实际失败。所以对我来说只是品味问题。
至于你的组件,他们会像这样使用钩子:
const Workshops = () =>
const isLoading, error, data: workshops = useMyDataFetch(api.get.workshops);
if ( error ) return <p> error.message </p>
if ( isLoading )
return <p>Loading workshops...</p>
return(
// the same here
);
export default Workshops
【讨论】:
一切正常,非常感谢!有没有办法在一个共享组件中隔离 Workshops 和 Shows 中的 return 语句中的内容?由于代码是相同的......我尝试使用 Context 但它只适用于二选一。 @MarcoMazzai 你的意思是JSX
部分吗?你可以只用一个组件来做这个,它需要一个带有api.get.workshops
或api.get.shows
作为值的道具。
或者它可能宁愿让责任不明确。可能您可能只是将 .map()
中的所有内容提取到 <Card />
之类的东西中,保持加载数据逻辑仍然在 Workshops
和 Shows
之间重复
是的,我指的是 JSX 部分。我尝试使用道具方式,但到目前为止我没有运气。以上是关于使用 React Hooks 在不同页面中获取请求的主要内容,如果未能解决你的问题,请参考以下文章
使用 React Hooks useEffect 发送 ajax 请求获取数据全攻略