1

I'm having some trouble with a dynamic route in Next JS, and navigating from one dynamic page to another.

I have a custom type called 'projects'. In that custom type I have set up a Content Relationship field from Prismic called 'relatedProject', so I can select another project in the CMS as a linked document at the end of each project page.

Displaying this related project works fine, and is displaying the correct information when I navigate to a project page, but when I click the link to take me to the related project document - which is the same dynamic route, just with different content, the content is not changing to the content that should be getting pulled in from the new project. A proper load doesn't occur as the page load animations are not playing when clicking the link. When I perform a hard refresh the page is rendering correctly with the content of the project page I clicked through to.

I'm unsure whether this is something wrong with Prismic or something wrong with Next JS? Apologies if I have not explained this brilliantly. I am sure getStaticPaths is setup correctly, as I can navigate to any other project page from the home or work pages, just not from one project page to another. Really has got me stumped!

This is my code for the dynamic page template [uid].js, any help is appreciated:

import { useEffect, useRef } from 'react';

import { createClient } from '../../prismic';
import resolver from '../../sm-resolver.js';
import * as prismicH from '@prismicio/helpers';
import { linkResolver } from '../../utils/linkResolver';
import { SliceZone } from '@prismicio/react';

import { gsap } from 'gsap';

import { Layout } from '../../components/Layout';
import ProjectHero from '../../components/Hero/Project';
import RelatedProjectCta from '../../components/RelatedProjectCta';

const ProjectDetail = ({ data, url, lang, layout }) => {

  const seo = {
    metaTitle: data.metaTitle || layout.metaTitle,
    metaDescription: data.metaDescription || layout.metaDescription,
    metaImage: data.metaImage?.url || layout.metaImage?.url,
    url: url,
    article: true,
    lang: lang,
  };

  const pageData = { data };
  
  const relatedProject = { data };

  const revealOverlay = useRef();

  // Hero reveal
  useEffect(() => {
    gsap.to(revealOverlay.current, {
      opacity: 0,
      duration: 2.3,
      ease: "power2.out"
    });
  }, []);

  return (
    <Layout seo={seo} {...layout}>

      <ProjectHero {...pageData} />

      <SliceZone slices={data.slices} resolver={resolver} />

      { 
        prismicH.isFilled.link(data.relatedProject) ? (
          <RelatedProjectCta {...relatedProject}/>
        )
        : null
      }
      
    </Layout>
  );
};

// Fetch content from prismic - previews but doesn't hot reload
export const getStaticProps = async ({ params, previewData }) => {
  const client = createClient({ previewData });

  // Default Layout components reused across the site
  // If a singleton document is missing, `getStaticProps` will throw a PrismicError.
  const seo = await client.getSingle("defaultSeo");
  const header = await client.getSingle("header");
  const footer = await client.getSingle("footer");
  const socials = await client.getSingle("socials");
  const projectDetail = await client.getByUID("project", params.uid, {'fetchLinks': 'project.theme, project.client, project.projectTitle, project.projectIntroduction, project.featuredImage'} );

  return {
    props: {
      layout: {
        seo,
        header,
        footer,
        socials,
      },
      ...projectDetail
    }
  };
};

export const getStaticPaths = async () => {
  const client = createClient();

  const projectDetail = await client.getAllByType("project");

  return {
    paths: projectDetail.map((page) => prismicH.asLink(page, linkResolver)),
    fallback: false,
  };
};

export default ProjectDetail;

This is the code of the component that is the link for the related project:

import React from 'react';
import { PrismicText } from '@prismicio/react';
import { PrismicNextImage } from '@prismicio/next';

import { Link } from "../Link";

const RelatedProjectCta = ({ data }) => {

  const relatedProject = {
    uid: data.relatedProject.uid,
    url: data.relatedProject.url,
    theme: data.relatedProject.theme,
    client: data.relatedProject.data.client,
    title: data.relatedProject.data.projectTitle,
    introduction: data.relatedProject.data.projectIntroduction,
    image: data.relatedProject.data.featuredImage,
  }

  return (
    <section className={`component cta-slice ${relatedProject.theme}`} data-header={relatedProject.theme === "light" && (`is-dark`) || relatedProject.theme === "dark" && ('is-light')}>
      <div className="container">
        <div className="cta-slice_text-wrapper">
          <div className="eyebrow-heading">
            Related project
          </div>
          <h2 className="primary-heading">
            <PrismicText field={relatedProject.client}/>
          </h2>
          <div className="description lead-body">
            <PrismicText field={relatedProject.title}/>
          </div>
          <Link
            href={`/work/${relatedProject.uid}`}
            className="btn animated-button">
            View project
          </Link>
        </div>
      </div>
      <div className="cta-slice_background">
        <div className="cta-slice_background_image">
          <PrismicNextImage
            className="block width-100% object-cover"
            field={relatedProject.image}
            imgixParams={{ q: 80 }}
            layout="fill"
          />
        </div>
      </div>
    </section>
  )
};

export default RelatedProjectCta

Link component:

import NextLink from "next/link";
import { asLink } from "@prismicio/helpers";
import { linkResolver } from "../utils/linkResolver";

export const Link = ({
  href: link,
  target,
  disabled,
  children,
  className,
  ...rest
}) => {
  if (disabled) {
    return <span {...rest}>{children}</span>;
  }

  //Standard link
  if (typeof link === "string") {
    if (link[0] === "/") {
      return (
        <NextLink href={link}>
          <a className={className} {...rest}>
            {children}
          </a>
        </NextLink>
      );
    }

    return (
      <a
        href={link}
        target={target ?? "_blank"}
        className={className}
        {...rest}
        rel="noopener noreferrer"
      >
        {children}
      </a>
    );
  }

  //Unknown link
  if (link.link_type === "Any") return null;

  //Prismic Link
  if (link.link_type === "Web") {
    if (!link.url) return null;

    //Same page anchor links
    if (link.url.includes("://#")) {
      const anchor = link.url.split("://")[1];
      return (
        <a href={anchor} className={className} {...rest}>
          {children}
        </a>
      );
    }

    return (
      <a
        href={asLink(link, linkResolver)}
        target={target ?? "_blank"}
        className={className}
        {...rest}
        rel="noopener noreferrer"
      >
        {children}
      </a>
    );
  }

  if (link.link_type === "Document") {
    return (
      <NextLink href={asLink(link, linkResolver)}>
        <a className={className} {...rest}>
          {children}
        </a>
      </NextLink>
    );
  }

  if (link.link_type === "Image") {
    return (
      <a
        href={asLink(link, linkResolver)}
        className={className}
        {...rest}
        rel="noopener noreferrer"
      >
        {children}
      </a>
    );
  }

  return null;
};

JonQuayle
  • 11
  • 4
  • Can you please add the code for the component/s that are responsible for the linking? We can't see much information related with your issue with the code you provided. – ivanatias Jul 14 '22 at 19:30
  • Sure @ivanatias, I have added the code for the related link component above. – JonQuayle Jul 14 '22 at 20:41
  • I can see you got a custom `Link` component, can you also provide the code for that component? – ivanatias Jul 14 '22 at 20:51
  • Thanks @ivanatias, link component is up in the question – JonQuayle Jul 14 '22 at 20:55
  • 1
    My guess is that the problem is actually in `getStaticPaths`. `paths` is an array that should contain an object with the key `params`, which at the same time is an object itself with `yourDynamicPageKey: value`, in your case: `uid: uidValue`. More information on the [docs](https://nextjs.org/docs/api-reference/data-fetching/get-static-paths) – ivanatias Jul 14 '22 at 21:27
  • Thanks for your suggestion @ivanatias, I have altered the getStaticPaths which now contains an array. Still getting the same problem. I'm also talking to Prismic about this as I wonder if its a bug in their code. – JonQuayle Jul 21 '22 at 11:56
  • 2
    Fixed it with adding a key to the props in getStaticProps. Figured it out from this post - https://github.com/vercel/next.js/issues/9992#issuecomment-615402511 for anyone who might be experiencing the same issue. – JonQuayle Jul 21 '22 at 15:12
  • Ah, this worked! Tysm! – Ismail Farooq Jan 02 '23 at 07:17

0 Answers0