Javascript 下一个JS构建是';不要把每一条路都建起来
摘要/问题 我使用Javascript 下一个JS构建是';不要把每一条路都建起来,javascript,reactjs,next.js,Javascript,Reactjs,Next.js,摘要/问题 我使用Nextjs创建了一个动画数据库应用程序,部署在Vercel上。构建很好,呈现了初始页面,但只有少数动态路由被呈现,其余显示404页面。我查看了部署日志,发现对于每个动态页面,每个动态路由只构建了10条路由 从Vercel部署屏幕截图 在开发过程中(localhost:3000),没有任何问题,一切正常 路线基于每个标题的id,有数千个标题 我的代码 下面是我使用getstaticpath和getStaticProps export const getStaticProps
Nextjs
创建了一个动画数据库应用程序,部署在Vercel
上。构建很好,呈现了初始页面,但只有少数动态路由被呈现,其余显示404页面。我查看了部署日志,发现对于每个动态页面,每个动态路由只构建了10条路由
从Vercel部署屏幕截图
在开发过程中(localhost:3000),没有任何问题,一切正常
路线基于每个标题的id
,有数千个标题
我的代码
下面是我使用getstaticpath
和getStaticProps
export const getStaticProps = async ({ params }) => {
const [anime, animeCharacters, categories, streaming, reviews] = await Promise.all([
fetch(`https://kitsu.io/api/edge/anime/${params.id}`),
fetch(`https://kitsu.io/api/edge/anime/${params.id}/characters`),
fetch(`https://kitsu.io/api/edge/anime/${params.id}/categories`),
fetch(`https://kitsu.io/api/edge/anime/${params.id}/streaming-links`),
fetch(`https://kitsu.io/api/edge/anime/${params.id}/reviews`),
])
.then((responses) =>
Promise.all(responses.map((response) => response.json()))
)
.catch((e) => console.log(e, "There was an error retrieving the data"))
return { props: { anime, animeCharacters, categories, streaming, reviews } }
}
export const getStaticPaths = async () => {
const res = await fetch("https://kitsu.io/api/edge/anime")
const anime = await res.json()
const paths = anime.data.map((show) => ({
params: { id: show.id },
}))
return { paths, fallback: false }
}
[id]
是我的动态路线,正如您所见,它只填充了10条路线(前3条和7条额外路线)
尽管有这么多的节目,我还是在每个节目上循环,获取它的ID,然后将其作为路径传递
我的想法
我使用的API就是API
在文档中,它表示:“默认情况下,资源以10为一组进行分页,最多可以增加到20”。我想这可能是生成10条路径的原因,但如果是这样,为什么它在生产和部署中都能正常工作?此外,当我点击每个海报图像时,它应该通过其id
将我带到特定的标题,这是动态的,因此最初生成多少资源并不重要
动态页面代码`/anime/[id]
import { useState } from "react"
import { useRouter } from 'next/router'
import fetch from "isomorphic-unfetch"
import formatedDates from "./../../helpers/formatDates"
import Navbar from "../../components/Navbar"
import TrailerVideo from "../../components/TrailerVideo"
import Characters from "./../../components/Characters"
import Categories from "../../components/Categories"
import Streamers from "../../components/Streamers"
import Reviews from "../../components/Reviews"
const Post = ({ anime, animeCharacters, categories, streaming, reviews}) => {
const [readMore, setReadMore] = useState(false)
const handleReadMore = () => setReadMore((prevState) => !prevState)
let {
titles: { en, ja_jp },
synopsis,
startDate,
endDate,
ageRating,
ageRatingGuide,
averageRating,
episodeCount,
posterImage: { small },
coverImage,
youtubeVideoId,
} = anime.data.attributes
const defaultImg = "/cover-img-default.jpg"
const synopsisSubString = () =>
!readMore ? synopsis.substring(0, 240) : synopsis.substring(0, 2000)
const router = useRouter()
if(router.isFallback) return <div>loading...</div>
return (
<div className='relative'>
<div className='z-0'>
<img
className='absolute mb-4 h-12 min-h-230 w-full object-cover opacity-50'
src={!coverImage ? defaultImg : coverImage.large}
/>
</div>
<div className='relative container z-50'>
<Navbar />
<div className='mt-16 flex flex-wrap md:flex-no-wrap'>
{/* Main */}
<div className='md:max-w-284'>
<img className='z-50 mb-6' src={small} />
<div className='xl:text-lg pb-6'>
<h1 className='mb-2'>Anime Details</h1>
<ul>
<li>
<span className='font-bold'>Japanese Title:</span> {ja_jp}
</li>
<li>
<span className='font-bold'>Aired:</span>{" "}
{formatedDates(startDate, endDate)}
</li>
<li>
<span className='font-bold'>Rating:</span> {ageRating} /{" "}
{ageRatingGuide}
</li>
<li>
<span className='font-bold'>Episodes:</span> {episodeCount}
</li>
</ul>
</div>
<Streamers streaming={streaming} />
</div>
{/* Info Section */}
<div className='flex flex-wrap lg:flex-no-wrap md:flex-1 '>
<div className='mt-6 md:mt-40 md:ml-6 lg:mr-10'>
<h1 className='sm:text-3xl pb-1'>{en}</h1>
<h2 className='sm:text-xl lg:text-2xl pb-4 text-yellow-600'>
{averageRating}{" "}
<span className='text-white text-base lg:text-lg'>
Community Rating
</span>
</h2>
<div>
<p className='max-w-2xl pb-3 overflow-hidden xl:text-lg'>
{synopsisSubString()}
<span className={!readMore ? "inline" : "hidden"}>...</span>
</p>
<button
className='text-teal-500 hover:text-teal-900 transition ease-in-out duration-500 focus:outline-none focus:shadow-outline'
onClick={handleReadMore}
>
{!readMore ? "Read More" : "Read Less"}
</button>
</div>
<Categories categories={categories} />
<Reviews reviews={reviews}/>
</div>
{/* Sidebar */}
<section className='lg:max-w-sm mt-10 md:ml-6 lg:ml-0'>
<TrailerVideo youtubeVideoId={youtubeVideoId} />
<Characters animeCharacters={animeCharacters} />
</section>
</div>
</div>
</div>
</div>
)
}
export const getStaticProps = async ({ params }) => {
const [anime, animeCharacters, categories, streaming, reviews] = await Promise.all([
fetch(`https://kitsu.io/api/edge/anime/${params.id}`),
fetch(`https://kitsu.io/api/edge/anime/${params.id}/characters`),
fetch(`https://kitsu.io/api/edge/anime/${params.id}/categories`),
fetch(`https://kitsu.io/api/edge/anime/${params.id}/streaming-links`),
fetch(`https://kitsu.io/api/edge/anime/${params.id}/reviews`),
])
.then((responses) =>
Promise.all(responses.map((response) => response.json()))
)
.catch((e) => console.log(e, "There was an error retrieving the data"))
return { props: { anime, animeCharacters, categories, streaming, reviews } }
}
export const getStaticPaths = async () => {
const res = await fetch("https://kitsu.io/api/edge/anime")
const anime = await res.json()
const paths = anime.data.map((show) => ({
params: { id: show.id },
}))
return { paths, fallback: true }
}
export default Post
从“react”导入{useState}
从“下一个/路由器”导入{useRouter}
从“同构取消蚀刻”导入提取
从“/./../helpers/formatDates”导入格式化日期
从“../../components/Navbar”导入导航栏
从“../../components/TrailerVideo”导入TrailerVideo
从“/./../components/Characters”导入字符
从“../../components/Categories”导入类别
从“../../components/Streamers”导入拖缆
从“../../components/Reviews”导入评论
const Post=({动画、动画角色、类别、流媒体、评论})=>{
const[readMore,setReadMore]=useState(false)
const handleReadMore=()=>setReadMore((prevState)=>!prevState)
让{
标题:{en,ja_jp},
提要
开始日期,
结束日期,
阿格拉廷,
阿格拉廷圭德,
平均而言,
情节数,
后期图像:{small},
封面图片,
YouTubevidoid,
}=anime.data.attributes
const defaultImg=“/cover img default.jpg”
const synopsisSubString=()=>
!readMore?大纲.子字符串(0240):大纲.子字符串(02000)
const router=useRouter()
如果(router.isFallback)返回加载。。。
返回(
{/*Main*/}
动漫细节
-
日文标题:{ja_jp}
-
播放:{“}
{格式化日期(开始日期,结束日期)}
-
评级:{ageRating}/{”“}
{Agratingguide}
-
情节:{eposodecount}
{/*信息部分*/}
{en}
{平均值}{”“}
社区评级
{synopsisSubString()}
...
{!阅读更多?“阅读更多”:“阅读更少”}
{/*侧边栏*/}
)
}
export const getStaticProps=async({params})=>{
const[动画、动画角色、类别、流媒体、评论]=等待承诺。全部([
取回(`https://kitsu.io/api/edge/anime/${params.id}`),
取回(`https://kitsu.io/api/edge/anime/${params.id}/characters`),
取回(`https://kitsu.io/api/edge/anime/${params.id}/categories`),
取回(`https://kitsu.io/api/edge/anime/${params.id}/streaming links`),
取回(`https://kitsu.io/api/edge/anime/${params.id}/reviews`),
])
。然后((回答)=>
Promise.all(responses.map((response)=>response.json())
)
.catch((e)=>console.log(e,“检索数据时出错”))
返回{道具:{动画、动画角色、类别、流媒体、评论}
}
export const getstaticpath=async()=>{
const res=等待获取(“https://kitsu.io/api/edge/anime")
const anime=wait res.json()
常量路径=anime.data.map((显示)=>({
参数:{id:show.id},
}))
返回{路径,回退:true}
}
导出默认帖子
错误截图
如果您正在使用的API以10人一组的形式提供资源,那么当您在
getstaticpath
中调用API时,您只提前了10个id
。在nextjs中使用静态生成在生产模式下提前为所有可用id构建静态页面。但在开发模式下,服务器将根据每个请求重新创建每个页面。因此,要解决这个问题,您可以构建前10个页面,并使其余页面成为回退页面。这是你怎么做的
export const getStaticPaths = async () => {
const res = await fetch("https://kitsu.io/api/edge/anime")
const anime = await res.json()
// you can make a series of calls to the API requesting
// the next page to get the desired amount of data (100 or 1000)
// how many ever static pages you want to build ahead of time
const paths = anime.data.map((show) => ({
params: { id: show.id },
}))
// this will generate 10(resource limit if you make 1 call because your API returns only 10 resources)
// pages ahead of time and rest of the pages will be fallback
return { paths, fallback: true }
}
请记住,在getstaticpath
中使用{fallback:true}
时,您需要有某种加载指示器,因为当您第一次发出请求时,页面将静态生成,其中
function MyPage = (props) {
const router = useRouter()
if (router.isFallback) {
// your loading indicator
return <div>loading...</div>
}
return (
// the normal logic for your page
)
}
const getStaticProps = async () => {
// your data fetching logic
// if fail
return {
props: {data: null, error: true, statusCode: 'the-status-code-you-want-to-send-(500 or 404)'}
}
// if success
return {
props: {data: 'my-fetched-data', error: false}
}
}
// in the page component
import ErrorPage from 'next/error';
function MyStaticPage(props) {
if (props.error) {
return <ErrorPage statusCode={404}/>
}
// else you normal page logic
}