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;
};