for contenxt, I’m building a website for a pet rescue charity, I’m using Next.js.
I’m new to Nextjs and can’t figure out how to get my button or a link to actually work propperly
I am currently getting a 404 error This page could not be found, when I’m trying to get the button to take me to another page I’ve built in my next app.
I’ve tried a few things.
Can someone help ??
here is the card component:
import React from 'react';
import Image from 'next/image';
import Button from '../components/Button';
import Link from 'next/link';
export default function PetCard({ pet, onClick }) {
return (
<div className="flex flex-col border p-4 rounded-lg hover:shadow-lg transition-shadow bg-white" >
<Link href="/[petId]" as={`/adote/${pet.name}`} passHref>
<Button
label="Ver perfil"
onClick={onClick}
className="bg-indigo-500 hover:bg-gray-600 focus-visible:outline-indigo-600 w-32 flex flex-row justify-center items-center"
/></Link>
</div>
)
}
The button is supposed to go to this petId page:
'use server'
import React from 'react';
import { useRouter } from 'next/router';
export default function PetDetailPage() {
const router = useRouter();
const pet = JSON.parse(router.query);
return (
<div className="p-4">
<Image src={pet.avatar} alt={pet.name} width={600} height={600} className="rounded-md" />
<h1 className="text-2xl font-bold mt-4">{pet.name}</h1>
<p className="text-gray-600">{pet.breed}</p>
<p className="text-gray-600">{pet.id}</p>
<p className="text-gray-600">{pet.age}</p>
<p className="text-gray-600">{pet.gender}</p>
<p className="mt-2">{pet.description}</p>
</div>
);
}
I don’t mind if its just a placeholder page for now. I have this mock data from a mock api I’ve made and it fetches with no issues on the main adoption page:
'use client';
import React from 'react';
import CustomizableHero from "../../components/HeroScondary";
import PetCard from "../../components/PetCard";
import Button from '../../components/Button';
import { useState, useEffect } from 'react'
export default function Adote() {
// mock API
const [pets, setPets] = useState([])
const [loading, setLoading] = useState(true)
const [page, setPage] = useState(1)
useEffect(() => {
const fetchPets = async () => {
setLoading(true)
const url = new URL('https://653bf08fd5d6790f5ec7a989.mockapi.io/pets')
url.searchParams.append('completed', false)
url.searchParams.append('page', page)
url.searchParams.append('limit', 18)
const res = await fetch(url)
const data = await res.json()
setPets(prevPets => [...prevPets, ...data])
setLoading(false)
}
fetchPets()
},
[])
if (loading) {
return <p>Loading...</p>
}
const handlePetClick = (petId) => {
router.push(`/adote/${petId}`)
}
return (
<div className="relative">
<CustomizableHero
backgroundImage="/images/dois-cachorros.png"
title="Adote"
subtitle="Encontre o seu melhor amigo"
color="white"
/>
{/* search filter */}
<div className="flex flex-row">
</div>
{/* pet cards */}
<div className="absolute w-[100vw] max-w-screen flex flex-col justify-center ">
<div className="flex flex-col text-align-center items-center justify-between m-10">
<h2 className="text-5xl font-bold tracking-tight sm:text-5xl text-gray-500 p-5">Animais buscando uma familia</h2>
<p className="mt-6 mb-3 text-md leading-8 text-gray-500 text-center p-5">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec euismod, nulla ut condimentum maximus, felis enim rhoncus justo, vel venenatis magna tortor nec tortor. Donec vulputate fermentum fermentum. Curabitur odio dui, consectetur vitae ornare eu, ultricies vel risus</p>
</div>
{/* Called displayPetCards() inside JSX code to render the PetCard components. */}
<div className="grid grid-cols-3 gap-4 m-10 p-5">
{pets.map(pet => (
<PetCard
key={pet.id}
pet={pet}
onClick={()=> handlePetClick(pet.id)}
/>
))}
</div>
<p className="flex flex-col text-center mt-5">Visualizados 18 de 661 animais de estimação</p>
<div className="flex justify-center m-10">
<Button
label="Mostrar mais"
onClick={() => setPage(page + 1)
} // Attach the click handler here
className="bg-indigo-500 hover:bg-gray-600 focus-visible:outline-indigo-600"
/>
</div>
</div>
</div>
);
};
I’ve tried useRouter, I’ve tried getServerSideProps() but nothing works
2
Answers
Heres a example code I made :
Explaination:
1st is Link tag
&2nd is a Button as link
pets folder
Folder Structure :
now I will show pets data, & from it i will pass ID to Link tag & Button component.
Button Component is client side bcoz of event click.
Now if someone clicks on link or button, they will get navigated to
pets/id
Using url present in code I appended id to it get details of pet by id. Details page is under folder
pets/[id]/page.js
You may read this for more clarity of concepts :
Routing Fundamentals :
https://nextjs.org/docs/app/building-your-application/routing
Dynamic Routes :
https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes
Linking and Navigating :
https://nextjs.org/docs/app/building-your-application/routing/linking-and-navigating
Server Components :
https://nextjs.org/docs/app/building-your-application/rendering/server-components
Client Components :
https://nextjs.org/docs/app/building-your-application/rendering/client-components
When to use Server and Client Components? :
https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#when-to-use-server-and-client-components
All Pets Detail Page:
projectNamesrcapppetspage.js
Pet Detail page :
projectNamesrcapppets[id]page.js
LinkButton.js Component
projectNamesrcappcompLinkButton.js
under comp folderInstead of using button you can style that Link tag to look like a button !
Output:
http://localhost:3000/pets/1
open Network Tab
click onpets
, then on right hand side click on preview you will see page is pre-rendered !Network Tab
click on preview you will see page is pre-rendered.Comment to ask for any doubts.
This code will be deleted from myside(personal computer).
Don’t overcomplicate things you are already passing pet.id in petCard component just link it from there
And then search pet for specific id in PetDetailPage by params