我正在使用React Hooks建立一个网站,并且我有两个不同的页面(Workshops.js和Shows.js)从同一API提取数据,只是使用不同的参数(?type = 0和?type = 1) )。 提取数据后,我便在映射结果(在那儿有一个可重用的组件会很好。请参阅下面代码中的注释)。当用户单击表演或工作室时,他将被重定向到同一页面。
现在,代码可以正常工作了。 有没有更优雅的方法来避免重复相同的代码? ...类似于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
答案 0 :(得分: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