就上下文而言,我正在为宠物救援慈善机构建立一个网站,我正在使用 Next.js。 我是 Nextjs 的新手,不知道如何让我的按钮或链接正常工作 当我尝试使用按钮将我带到我在下一个应用程序中构建的另一个页面时,我当前收到 404 错误“找不到此页面”。
我尝试了一些方法。
有人可以帮忙吗??
这是卡片组件:
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>
)
}
该按钮应该转到此 petId 页面:
'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>
);
}
我不介意它现在是否只是一个占位符页面。我从我制作的模拟 api 中获取了这些模拟数据,并且在主要采用页面上获取时没有任何问题:
'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>
);
};
我尝试过 useRouter,我尝试过 getServerSideProps() 但没有任何效果
这是我制作的示例代码: 说明:
1st is Link tag
& 2nd is a Button as link
pets folder
文件夹结构:
projectName
├── .gitignore
├── jsconfig.json
├── next.config.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
│ ├── images
│ ├── next.svg
│ └── vercel.svg
├── README.md
├── src
│ └── app
│ ├── api
│ ├── comp
│ │ ├── LinkButton.js
│ ├── favicon.ico
│ ├── globals.css
│ ├── layout.js
│ ├── page.js
│ ├── pets
│ │ ├── page.js
│ │ └── [id]
│ │ └── page.js
└── tailwind.config.js
现在我将显示宠物数据,并从中将 ID 传递给链接标签和按钮组件。
按钮组件是事件点击的客户端 bcoz。
现在,如果有人点击链接或按钮,他们将被导航到
pets/id
使用代码中存在的 url,我在其中附加了 id,通过 id 获取宠物的详细信息。详细信息页面位于文件夹
pets/[id]/page.js
下
您可以阅读本文以获得更清晰的概念:
路由基础知识: https://nextjs.org/docs/app/building-your-application/routing
动态路线:
https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes
链接和导航:
https://nextjs.org/docs/app/building-your-application/routing/linking-and-navigating
服务器组件:
https://nextjs.org/docs/app/building-your-application/rendering/server-components
客户端组件:
https://nextjs.org/docs/app/building-your-application/rendering/client-components
何时使用服务器和客户端组件? :
https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#when-to-use-server-and-client-components
所有宠物详细信息页面:
projectName\src\app\pets\page.js
import Link from "next/link"
import LinkButton from "../comp/LinkButton"
async function GetPets() {
let data = await fetch('https://653bf08fd5d6790f5ec7a989.mockapi.io/pets')
let PetsData = await data.json()
// console.log(PetsData);
// LOGGED IN TERMINAL BCOZ ITS SERVER-SIDE
return PetsData
}
export default async function Pets() {
const PetsData = await GetPets()
return (
<div>
<h1>All Pets !</h1>
{
PetsData.map((p, i) => {
return (
<div style={{
border: "1px solid black",
padding: "25px",
margin: '25px'
}}
key={i}
>
<img src={p.avatar} width="250" alt="" />
<h3>{p.name}</h3>
<Link style={{ color: "blue" }} href={`/pets/` + p.id}> VIew </Link>
<LinkButton ID={p.id} />
</div>
)
})
}
</div>
)
}
宠物详细信息页面:
projectName\src\app\pets\[id]\page.js
async function GetDetailsByID(ID) {
let data = await fetch('https://653bf08fd5d6790f5ec7a989.mockapi.io/pets/' + ID)
// I GOT THIS URL BY TRYING TO APPEND ID TO URL PROVIDED IN CODE
let PetDetails = await data.json()
// console.log(Object.keys(PetDetails));
// LOGGED IN TERMINAL BCOZ ITS SERVER-SIDE
return PetDetails
}
export default async function DetailsPage({ params }) {
let Details = await GetDetailsByID(params.id)
// AFTER GETTING ID I WILL PASS IT THE API CALL
// THIS PAGE WILL BE SERVER RENDERED
return (
<div>
<h1>Full Pet Deyails :</h1>
<img src={Details.avatar} alt="" />
<p className="text-gray-600">{Details.name}</p>
<p className="text-gray-600">{Details.id}</p>
<p className="text-gray-600">{Details.age}</p>
<p className="text-gray-600">{Details.Gender}</p>
<p className="text-gray-600">{Details.breed}</p>
<p className="text-gray-600">{Details.description}</p>
<p className="text-gray-600">{Details.createdAt}</p>
</div>
)
}
LinkButton.js 组件
projectName\src\app\comp\LinkButton.js
comp 文件夹下
'use client'
import { useRouter } from 'next/navigation'
import React from 'react'
const LinkButton = ({ ID }) => {
const MyRouter = useRouter()
// IF YOU WANT TO USE A BUTTON THEN IT COMES UNDER CLIENT SIDE
// RENDERING BECAUSE OF CLICK EVENT
// HERE IM PASSING THE ID TO LINK & USING ROUTER TO NAVIGATE
return (
<button onClick={() => {
MyRouter.push(`/pets/` + ID)
}}>
Button
</button>
)
}
export default LinkButton
您可以将链接标签设置为看起来像按钮,而不是使用按钮!
输出:
http://localhost:3000/pets/1
open Network Tab
单击pets
,然后在右侧单击预览,您将看到页面已预渲染!Network Tab
中单击预览,您将看到页面已预渲染。如有疑问请评论。
此代码将从我这边删除。