React newcomer here.
I'm loading Astronomy Picture of the Day in a component using a loading spinner. I want the page to get data every time I call it from navbar but it's flashing old data before showing the spinner.
How to avoid this behavior? I don't want to use ComponentWillMount because it's deprecated and I'm using functions.
The component code:
import { useEffect, useContext } from 'react'
import { getApod } from '../context/nasa/NasaActions'
import NasaContext from '../context/nasa/NasaContext'
import Spinner from './layout/Spinner'
function Apod() {
const {loading, apod, dispatch} = useContext(NasaContext)
useEffect(() => {
dispatch({type: 'SET_LOADING'})
const getApodData = async() => {
const apodData = await getApod()
dispatch({type: 'SET_APOD', payload: apodData})
}
getApodData()
}, [dispatch])
const {
title,
url,
explanation,
} = apod
if (loading) { return <Spinner /> }
return (
<div>
<h2>{title}</h2>
<img src={url} className='apod' alt='apod'/>
<p>{explanation}</p>
</div>
)
}
export default Apod
Github repository: https://github.com/BrunoCanongia/Apod-React
Deployed app: https://apod-react.vercel.app/
You can see this behavior clicking About and then clicking APOD again.
Thanks for your time.
CodePudding user response:
I had an idea, to clean the object in Context using onClick on the navbar button. Is this the best way? I don't know but it's working as I wanted.
import NasaContext from '../../context/nasa/NasaContext'
import { useContext } from 'react'
import { Link } from 'react-router-dom'
import logo from './assets/logo.png'
function Navbar() {
const {dispatch} = useContext(NasaContext)
const resetApod = () => {
const pathname = window.location.pathname
if ( pathname !== '/' ) {
dispatch({type: 'SET_APOD', payload: {}})
}
}
return (
<div className="navbar">
<div className="navbar-logo">
<img src={logo} alt='Experimentum'/>
</div>
<div className="navbar-menu">
<Link to='/' onClick={resetApod}>APOD </Link>
<Link to='/about'>ABOUT </Link>
</div>
</div>
)
}
export default Navbar
CodePudding user response:
I suggest you another solution to keep your navbar clean.
You can declare an instance variable loaded
using the useRef
hook. This variable will be initialized to false and set to true as soon as the apod is dispatched to your store.
import { useContext, useRef } from 'react'
function Apod() {
const {loading, apod, dispatch} = useContext(NasaContext)
const loaded = useRef(false);
useEffect(async () => {
dispatch({type: 'SET_LOADING'})
const apodData = await getApod()
loaded.current = true;
dispatch({type: 'SET_APOD', payload: apodData})
}, [dispatch])
const {title, url, explanation} = apod
if (!loaded.current || loading) { return <Spinner /> }
return (
<div>
<h2>{title}</h2>
<img src={url} className='apod' alt='apod'/>
<p>{explanation}</p>
</div>
)
}
export default Apod;