Epic Next.js 14 Tutorial: Learn Next.js by building a real-life project part 3

In part 3 of our series, let's finish building out our home page. We will finish up our Hero Section, then move to our Features Section, and finally add our Top Navigation and Footer.


This is a companion discussion topic for the original entry at https://strapi.io/blog/epic-next-js-14-tutorial-learn-next-js-by-building-a-real-life-project-part-3

Hi Paul,

I need a little help with header component. I’m getting the following TypeError after adding header component.

 
  ⨯ src/components/custom/Header.tsx (26:30) @ url
  ⨯ TypeError: Cannot read properties of undefined (reading 'url')
     at Header (./src/components/custom/Header.tsx:29:37)
     at stringify (<anonymous>)
 digest: "735238440"
   24 |       <Logo text={logoText.text}/>
   25 |       <div className="flex items-center gap-4">
 > 26 |         <Link href={ctaButton.url}><Button>{ctaButton.text}</Button></Link>
      |                              ^
   27 |       </div>
   28 |     </div>
   29 |   );

And here’s my Header.tsx code:

import Link from "next/link";
import { Logo } from "@/components/custom/Logo";
import { Button } from "@/components/ui/button";

interface HeaderProps {
  data: {
    logoText: {
      id: number;
      text: string;
      url: string;
    };
    ctaButton: {
      id: number;
      text: string;
      url: string;
    };
  };
}

export async function Header({ data }: Readonly<HeaderProps>) {
  const { logoText, ctaButton } = data;
  return (
    <div className="flex items-center justify-between px-4 py-3 bg-white shadow-md dark:bg-gray-800">
      <Logo text={logoText.text}/>
      <div className="flex items-center gap-4">
        <Link href={ctaButton.url}><Button>{ctaButton.text}</Button></Link>
      </div>
    </div>
  );
}

The logoText.text outputs just fine, only ctaButton has this issues. I doubled check the created component in Strapi to make sure it’s using the same model as logoText but can’t find what’s wrong?

Can you help me troubleshoot this?

Thank you.

1 Like

Here’s a screenshot of my Strapi heade model.

Hello Paul,

Thanks for the work you’ve done working on this blog posts !
I have a question regarding the flattenAttributes helper.
Is there a way to properly type it using the types generated by the strapi typescript command ?

I have been reading : Improve Your Frontend Experience With Strapi Types And TypeScript that provide a way to type strapi responses (e.g: with APIResponseCollection<"api::post.post">) and I try to find a way to use it to generically type the flattenAttributes helper.

Thanks in advance !

1 Like

Double check that your query params are correct in the loaders.ts file inside the getGlobalPageData function.

export async function getGlobalPageData() {

  const url = new URL("/api/global", baseUrl);

  url.search = qs.stringify({
    populate: [
      "header.logoText",
      "header.ctaButton",
      "footer.logoText",
      "footer.socialLink",
    ],
  })

  const data = await fetchData(url.href);
  return data;

}

Also, console log the return and see what you are getting.

And finally double check that you have data in the field in Strapi Admin.

Let me know if this helped.

At the moment, there isn’t a straightforward solution, at least at my level of TS understanding. Know that in v5, we are going to be getting back the simplified response, so there will be no need for the flattentAttribute function that I am using.

I used it in this tutorial because when Strapi 5 was out, I wanted to have an easier time migrating the project. Ince the response will mainly mimic what the flattenAttributes function returns.

Once Strapi 5 is released, we’ll be working on an SDK that will significantly simplify the process of using Strapi types. This development will make our work with Strapi even more straightforward and user-friendly, enhancing our overall development experience.

I have the same code and data is populated in the Strapi. I guess something went wrong at the Strapi side and it’s not got recorded in to the database. I can try to remove the header model and its data nad start over.

Thank you for trying to help.

Hi Paul , Thank you very much vor this real-ife project . I treally helps understanding the use of Strapi in Next.js . I am struggling with a Readt hydration error . I believe I followed all of your steps but I am receiving this error


It come from th StrapiImage component
“use client”; // Ensures this component is rendered on the client side

import Image from “next/image”;
import { getStrapiMedia } from “@/lib/utils”;

interface StrapiImageProps {
src: string;
alt: string;
height: number;
width: number;
className?: string;
}

export function StrapiImage({
src,
alt,
height,
width,
className,
}: Readonly) {
if (!src) return null;
const imageUrl = getStrapiMedia(src);
const imageFallback = https://placehold.co/${width}x${height};

return (
<Image
src={imageUrl ?? imageFallback}
alt={alt}
height={height}
width={width}
className={className}
/>
);
}
Can you please help me with this ?

Here is the component from the project for the image component, I am not using “use client” directive.

import Image from "next/image";
import { getStrapiMedia } from "@/lib/utils";

interface StrapiImageProps {
  src: string;
  alt: string;
  height: number;
  width: number;
  className?: string;
}

export function StrapiImage({
  src,
  alt,
  height,
  width,
  className,
}: Readonly<StrapiImageProps>) {
  if (!src) return null;
  const imageUrl = getStrapiMedia(src);
  const imageFallback = `https://placehold.co/${width}x${height}`;

  return (
    <Image
      src={imageUrl ?? imageFallback}
      alt={alt}
      height={height}
      width={width}
      className={className}
    />
  );
}

What page (route) are you on when you get this error, is this on the home page?