Ionic-framework: Ionic React history.push/routerLink doesn't update the page

Created on 25 Mar 2020  路  6Comments  路  Source: ionic-team/ionic-framework

Hey guys! I'm building an app with Ionic React. I have a master page that displays a list of news, and a detail page displaying a single news. On the news detail page, I have a lit of random news displayed underneath the main news at the top.

Switching from the master page to the detail page works fine. I use the routerLink prop on an IonicCard and that works fine. But on the single news page, the list of news when clicked on, flicks the page, updates the URL but doesn't update the view. I have to manually reload the page for it to send the request to fetch the new news detail. You'll find the single news component code below:

import React, { useEffect } from 'react'

import {
  IonButtons,
  IonContent,
  IonHeader,
  IonMenuButton,
  IonPage,
  IonTitle,
  IonToolbar,
  IonCard,
  IonIcon,
  IonCardContent,
  IonCardSubtitle,
  IonCardHeader,
  IonCardTitle,
  IonLoading,
  IonGrid,
  IonRow,
  IonCol,
} from '@ionic/react'

import {
  FacebookShareButton,
  TwitterShareButton,
  TelegramShareButton,
  WhatsappShareButton,
  TelegramIcon,
  WhatsappIcon,
  FacebookIcon,
  TwitterIcon,
} from 'react-share'

import useSingleNews from '../hooks/useSingleNews'
import { RouteComponentProps, Redirect } from 'react-router'
import NewsInterface from '../interfaces/NewsInterface'
import SEO from '../components/SEO'
import { TWITTER_HANDLE } from '../utils/constants'
import colors from '../utils/colors'

interface Props extends RouteComponentProps<{
  newsHash: string
}> { }

const SingleNews: React.FC<Props> = ({ match }) => {
  const { data, loading, error } = useSingleNews(match.params.newsHash)

  useEffect(() => {
    console.log(data)
  }, [data])

  if (loading) return <IonLoading
    isOpen={loading}
    message={`Patientez s'il vous pla卯t...`}
  />

  if (error) return <Redirect to="/404" />

  const ShareButtons = () => {
    const url = window.location.href
    const title = `${data?.title} - Ha茂ti Info Toutan (HIT)`
    const hashtags = `HIT partage news`

    return (
      <IonRow>
        <IonCol>
          <FacebookShareButton
            url={url}
            quote={title}
            hashtag={hashtags.split(' ').join(' #')}>
            <FacebookIcon size={48} style={{ borderRadius: 4, color: colors.facebook }} />
          </FacebookShareButton>
        </IonCol>
        <IonCol>
          <TwitterShareButton
            url={url}
            title={title}
            via={TWITTER_HANDLE}
            hashtags={hashtags.split(' ')}>
            <TwitterIcon size={48} style={{ borderRadius: 4, color: colors.twitter }} />
          </TwitterShareButton>
        </IonCol>
        <IonCol>
          <WhatsappShareButton url={url} title={title}>
            <WhatsappIcon size={48} style={{ borderRadius: 4, color: colors.whatsapp }} />
          </WhatsappShareButton>
        </IonCol>
        <IonCol>
          <TelegramShareButton url={url} title={title}>
            <TelegramIcon size={48} style={{ borderRadius: 4, color: colors.telegram }} />
          </TelegramShareButton>
        </IonCol>
      </IonRow>
    )
  }

  return (
    <IonPage>
      <IonHeader>
        <IonToolbar>
          <IonButtons slot="start">
            <IonMenuButton />
          </IonButtons>
          <IonTitle>{data?.title} - HIT</IonTitle>
        </IonToolbar>
      </IonHeader>

      <IonContent>
        <IonGrid>
          <IonRow>
            <IonCol key={data?.hash} size="12" sizeSm="6">
              <IonCard>
                {!!data?.image_url && (<img src={data?.image_url} alt={data?.title} />)}
                <IonCardHeader>
                  <IonCardSubtitle>{data?.public_date}</IonCardSubtitle>
                </IonCardHeader>
                <IonCardContent>
                  <div dangerouslySetInnerHTML={{ __html: `${data?.body}` }} />
                </IonCardContent>
                {!!data?.ads && (
                  <IonCardHeader>
                    <IonCardSubtitle>
                      <div dangerouslySetInnerHTML={{ __html: `${data?.ads}` }} />
                    </IonCardSubtitle>
                  </IonCardHeader>
                )}

                <IonCardHeader>
                  <ShareButtons />
                </IonCardHeader>
              </IonCard>
            </IonCol>
          </IonRow>


          {data?.randoms ? (
            <>
              <h3 className="ion-padding-horizontal">Autres Nouvelles</h3>
              <IonRow>
                {data?.randoms.map((news: NewsInterface) => (
                  <IonCol key={news.hash} size="12" sizeSm="4" sizeXl="3">
                    <IonCard routerLink={`/n/${news.hash}`}>
                      {!!news.image_url && (<img src={news.image_url} alt={news.title} />)}
                      <IonCardHeader>
                        <IonCardSubtitle>{news.public_date}</IonCardSubtitle>
                        <IonCardTitle>{news.title}</IonCardTitle>
                      </IonCardHeader>
                    </IonCard>
                  </IonCol>
                ))}
              </IonRow>
            </>
          ) : null}
        </IonGrid>
      </IonContent>

      <SEO
        title={`${data?.title}`}
        url={window.location.href}
        description={`${data?.body.split('\n')[0]}`}
        image={data?.image_url}
      />
    </IonPage>
  )
}

export default SingleNews
triage

Most helpful comment

Ya, checkout our lifecycle guide which has some info around this: https://ionicframework.com/docs/react/lifecycle

Though, I think in this case, since you were navigating to the same page it was sticking around.

All 6 comments

Hi @jgb-solutions,

I'm not seeing anything in particular in the SingleNews component to cause issues. Would you be able to provide a slimmed down github repo that reproduces the issue?

hey @elylucas thanks for taking the time to respond.

I just made the project repo public here: https://github.com/jgb-solutions/HIT-APP.

@jgb-solutions

Thanks!

I wasn't able to get the http request to fire to the news service, but looking through the code I think the issue might be in the useSingleNews hook. The useEffect hook in there takes an empty array param, so it would only call fetchSingleNews once. I think if you passed the hash into the array it would call it each time the hash updates and pull back new data.

  useEffect(() => {
    fetchSingleNews()
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [newsHash])

Let me know if that fixes it.

hey @elylucas thanks a ton! It worked. Even tho I don't fully understand why, because I thought that each update of the route, would trigger a re-render of the page, and then make a request using a new instance of the hook. But it seems that that's not what's happening.

Anyway thanks a lot! I've been wondering why it wouldn't work for days.

Ya, checkout our lifecycle guide which has some info around this: https://ionicframework.com/docs/react/lifecycle

Though, I think in this case, since you were navigating to the same page it was sticking around.

Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

daveshirman picture daveshirman  路  3Comments

danbucholtz picture danbucholtz  路  3Comments

brandyscarney picture brandyscarney  路  3Comments

alexbainbridge picture alexbainbridge  路  3Comments

MrBokeh picture MrBokeh  路  3Comments