Search code examples
next.jscontentfulcontentful-api

How to make a conditional graphql request in NextJS getstaticprops?


I currently have a black friday page. Only when this black friday page is expired (must get the expired date from a query before) do i want it to query the expired page data.

Essentially i'm looking to make the query more efficient. Where the expired data wouldn't be pulled for no reason, and vice versa (page data query if expired). If any of this is possible.

The only working code i have is to query both data (black friday page and expired page data)

export async function getStaticPaths() {
  const blackFridaylugs = await ContentfulApi.getBlackFridaySlugs();

  const paths = blackFridaySlugs.map((item) => ({
    params: { slug: item.slug }
  }));

  return {
    paths,
    fallback: "blocking"
  };
}

export async function getStaticProps({ preview = false, params, previewData }) {
  const page = await ContentfulApi.getBlackFridayPromoBySlug(params.slug, {
    preview,
    enviroment: previewData?.enviroment
  });

  const expiredPage = await ContentfulApi.getPageContentBySlug(
    "expired-page",
    {
      preview,
      enviroment: previewData?.enviroment
    }
  );

  const globalSettings = await ContentfulApi.getGlobalSettings({ preview });

  return {
    props: {
      page,
      expiredPage,
      globalSettings
    },
    revalidate: 100
  };
}

function BlackFridayPages({ page, expiredPage, globalSettings }) {
  const [expired, setExpired] = useState(false);
  const promoExpired = new Date() - new Date(page?.promoEnd) < 0;

  useEffect(() => {
    if (promoExpired) {
      setExpired(false);
    } else {
      setExpired(true);
    }
  }, [promoExpired]);

  if (!expired)
    return (
      <ExpiredPage expiredPage={expiredPage} />
    );

  return (
    <>
     <BlackFridayPage /> 
    </>

  );
}


export default BlackFridayPages;


Solution

  • It says ReferenceError: expiredPage is not defined because you define that variable inside the scope of an if-statement, but try returning it outside of it inside the props object.

    Also, you cannot return solely expiredPage inside the if statement. It has to be returned as a key of props, just as you do at the bottom getStaticProps already.

    This should work:

    export async function getStaticProps({ preview = false, params, previewData }) {
      const page = await ContentfulApi.getBlackFridayPromoBySlug(params.slug, {
        preview,
        enviroment: previewData?.enviroment,
      });
    
      const promoExpired = new Date() - new Date(page?.promoEnd) < 0;
    
      // define the constant inside the function's scope
      // and only perform the HTTP request if promoExpired is true
      const expiredPage = promoExpired
        ? await ContentfulApi.getPageContentBySlug("expired-page", {
            preview,
            enviroment: previewData?.enviroment,
          })
        : null; 
    
      const globalSettings = await ContentfulApi.getGlobalSettings({ preview });
    
      return {
        props: {
          expiredPage,
          page: expiredPage ? null : page,
          globalSettings,
        },
        revalidate: 100,
      };
    }
    
    

    I also think there's some room for optimization of the way you conditionally display the two pages, because by relying on state that gets manipulated by useEffect, Next can't pre-render this page, as useEffect doesn't run on the server-side.

    So because you initialize expired as false, this will always pre-render ExpiredPage.

     if (!expired)
        return (
          <ExpiredPage expiredPage={expiredPage} />
        );
    
      return (
        <>
         <BlackFridayPage /> 
        </>
      );
    

    It would be better to not use useEffect in this case and imply whether it expired or not from the value of the passed props, somewhat like this:

    if (page == null) 
        return (
          <ExpiredPage expiredPage={expiredPage} />
        );
    
      return (
        <>
         <BlackFridayPage /> 
        </>
      );