I'm making a portfolio site using Next JS and motion, for the projects section I'm animating project cards using whileInView
. it is working fine but when I do soft navigation and move to the more projects screen it is not being triggered. It also works when I do a hard refresh.
See this in action here
projects.tsx
import { cn } from "@/lib/utils";
import Wrapper from "@/components/shared/page";
import { ProjectCard } from "./project-card";
import { Button } from "@/components/ui/button";
import { ArrowRight } from "lucide-react";
import Link from "next/link";
import { ROUTES } from "@/lib/constants/routes";
export function Projects({
className,
showMoreButton
}: {
className?: string;
showMoreButton?: boolean;
}) {
return (
<section className={cn("py-24 sm:px-8 bg-accent my-6", className)}>
<Wrapper className="px-4 space-y-20">
...
<ProjectCard
title={"Wall of wonder"}
imgUrl={"/images/project-1.webp"}
skipMargin
/>
... {/* without skipMargin */}
</Wrapper>
</section>
);
}
project-card.tsx
"use client";
import { cn } from "@/lib/utils";
import { motion } from "motion/react";
import Image from "next/image";
import { useRef } from "react";
export const ProjectCard = ({
reverse,
imgUrl,
title,
skipMargin
}: {
title: string;
reverse?: boolean;
imgUrl: string;
skipMargin?: boolean;
}) => {
const scrollRef = useRef<HTMLDivElement>(null);
return (
<article
ref={scrollRef}
className="max-sm:space-y-4 overflow-hidden sm:grid sm:grid-cols-10 gap-4"
>
<motion.div
initial={{
translateX: reverse ? "-20px" : "20px",
opacity: 0
}}
whileInView={{
translateX: "0px",
opacity: 1
}}
viewport={{
root: scrollRef,
margin: skipMargin ? undefined : "-100px",
once: true
}}
transition={{
ease: "easeInOut",
duration: "0.5",
delay: 0.1
}}
...
>
...
</motion.div>
<motion.div
...
initial={{
translateX: reverse ? "20px" : "-20px",
opacity: 0
}}
whileInView={{
translateX: "0px",
opacity: 1
}}
viewport={{
root: scrollRef,
margin: skipMargin ? undefined : "-100px",
once: true
}}
transition={{
ease: "easeInOut",
duration: "0.5",
delay: 0.1
}}
>
<Image
src={imgUrl}
...
/>
</motion.div>
</article>
);
};
Pages:
// Home
const Home = () => ... <Projects /> ...;
const Projects = ()=> <Projects />;
Working solution from the GitHub:
After some further testing, it appears to only happen when running NextJS in dev mode (with or without turbopack) If I build the site and run it it appears to work as intended. So annoying during development, but at least the actual build works correctly.