Home > Enterprise >  How to dispatch to Reducer before React renders component?
How to dispatch to Reducer before React renders component?

Time:12-28

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;
  • Related