I am new to Next.js and
I've been trying to to use getStaticProps in my dynamic pages in my Next.js app
and I get this error:
Error: getStaticPaths is required for dynamic SSG pages and is missing
for '/query/[itmid]'
[itmid].jsx
function Query({ posts }) {
return (
{posts.map((itm, k) => {
return (
<>
<Head>
<title> {itm.Name} - wixten </title>
</Head>
<div key={itm._id} className="Question-one">
<h1> {itm.Name}</h1>
<h2>{itm.Summary}</h2>
</div>
<div className="username">
<span className="username2">--{itm.username}</span>
</div>
</>
);
})}
</>
<div className="multi-container">
<Answershooks id={gotid} />
<RealtedPost />
</div>
</>
);
}
export async function getStaticProps() {
const res = await fetch("https://ask-over.herokuapp.com/questone/" + gotid);
console.log("check");
console.log("dada");
const posts = await res.json();
return {
props: {
posts,
},
};
}
export default Query;
Why am I getting this error?
What getStaticProps does is to generate the static page, but you need to tell next js, what are the paths to generate?
export async function getStaticPaths() {
return {
paths: [
{ params: { query: 'slug-1' }},
{ params: { query: 'slug-2' }}
],
fallback: true // false or 'blocking'
};
}
Then in your getStaticProp
export async function getStaticProps({ params }) {
//params.query will return slug-1 and slug-2
const res = await fetch("https://ask-over.herokuapp.com/questone/" + params.query);
console.log("check");
console.log("dada");
const posts = await res.json();
return {
props: {
posts,
},
};
}
You need to use params.query if you name your file [query].js.
The above codes will generate static paths /slug-1 and /slug-1.
If you are not trying to generate static pages (which seems like it), then you should probably use getServerSideProps which generates page on the go.
Related
This is my first time using NextJS and I'm trying to load 3 random dog breed images onto the app's webpage using the Dog.ceo API. I am able to see the three random dogs in the console from the console.log(data) line, but the images aren't being displayed. In this API there are only two properties - message (containing the image URL) and status (displaying 'success'). Any help in how to get these images to display? Also to note, I'm not using Typescript for this.
const defaultEndpoint = "https://dog.ceo/api/breeds/image/random/3";
export async function getServerSideProps() {
const res = await fetch(defaultEndpoint);
const data = await res.json();
return {
props: { data },
};
}
export default function Home({ data }) {
console.log("data", data);
const { results = [] } = data;
return (
<div className={styles.container}>
<Head>
<title>Dog Breed App</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
<div className="grid">
{results.map((result) => {
const { message } = result;
return (
<div key={message}>
<img src={message} alt=""></img>
</div>
);
})}
</div>
</main>
</div>
);
}
I tried using "message" from the "data" variable to get the url for the image. But that isn't working.
It's just a destructuring error. You have const { results = [] } = data;.
That line says: Find the property in my data object called results and if it doesn't exist, set it to an empty array. Your data object doesn't have a property called results. It has a property called message.
You could change this line to const { message = [] } = data and then just loop over the message array or you could just store the message array in the props.data property like this:
export async function getServerSideProps() {
const res = await fetch('https://dog.ceo/api/breeds/image/random/3');
// Destructure the response object here and
// rename the 'message' property as 'data'
const { message: data } = await res.json();
return {
props: { data },
};
}
// Destructure the props object to have access to the
// property named data:
export default function Home({ data }) {
return (
<main>
<div className="grid">
{data.map((img) => (
<div key={img}>
<img src={img} alt="dog"></img>
</div>
))}
</div>
</main>
);
}
you can use useEffect hook to load data and update to a state dogs. This will update render once on component creation.
const defaultEndpoint = "https://dog.ceo/api/breeds/image/random/3";
import React, { useState, useEffect } from 'react'
export default function Home({ data }) {
const [dogs, setDogs] = useState([]);
export async function getServerSideProps() {
const res = await fetch(defaultEndpoint);
const data = await res.json();
console.log("data", data);
setDogs(data)
}
useEffect(() => {
getServerSideProps()
}, [])
return (
<div className={styles.container}>
<Head>
<title>Dog Breed App</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
<div className="grid">
{dogs.map((result) => {
const { message } = result;
return (
<div key={message}>
<img src={message} alt=""></img>
</div>
);
})}
</div>
</main>
</div>
);
}
I'll suggest using [dependencies] in useEffect to control when it re-renders it like below
useEffect(() => {
//
return () => {
//
}
}, [dependencies])
I am working in nextjs, i am trying to make "dynamic routes",
i want after click my url should be like "myurl.com/article/55"
for this i use following "link tag"
<Link href={{pathname: "article/[id]",query: { id: post.id },}}>
<a className="rdmre-btn"> Read More</a>
</Link>
And here is my code in ("pages/article/[slug].js) in file,Where i am wrong ? i want whenever i click on any blog then blog details page should open.
import Axios from "axios";
import { useRouter } from "next/router";
import Link from "next/link";
import LatestBlogs from "../../components/LatestBlogs/LatestBlogs";
const Post = ({ post }) => {
const router = useRouter();
const htmlString = post.description_front;
if (router.isFallback) {
return <div>Loading...</div>;
}
return (
<>
<header className="bgbanner blog_header">
<div className="container cont">
<div className="header">
</div>
</div>
<div className="container "></div>
</header>
<section>
<div className="container Blog_page_sidebar">
<div className="blog_details">
<div className="blog_image">
<img src={post.image} />
</div>
<div className="blog_heading">
<h2>{post.title}</h2>
</div>
<div className="blog_detail">
<div
className="product-des"
dangerouslySetInnerHTML={{ __html: htmlString }}
/>
</div>
</div>
</div>
</section>
</>
);
};
export default Post;
export const getStaticProps = async ({ params }) => {
const { data } = await Axios.get(
`https://myurl.com/api/blogbyids/${params.id}`
);
const post = data;
return {
props: {
post,
},
};
};
export const getStaticPaths = async () => {
const { data } = await Axios.get(
"myurl.com/admin-panel/api/blogs"
);
const posts = data.slice(0, 10);
const paths = posts.map((post) => ({ params: { id: post.id.toString() } }));
return {
paths,
fallback: true,
};
};
[slug] is used to have nested routes. But correct is [...slug].js (info)
Example: myurl.com/article/[id]/[otherid]
In the example above we can see that in [id] can be nested children. You can name this param as you want.
If you want to have your structure as myurl.com/article/55, you need to have structure as follow:
In your pages folder:
You create a folder article (pages/article)
You create 2 files: index.js (or .tsx) and [id].js (you can name as [slug].js or [specialId].js - no matter the name
After, you are getting info with param name created.
Here is example of the code (URL: myurl.com/article/55; file: pages/article/[pid].js)
import { useRouter } from 'next/router'
const Post = () => {
const router = useRouter()
//same name as name of your file, can be [slug].js; [specialId].js - any name you want
const { pid } = router.query
//result will be '55' (string)
return <p>Post: {pid}</p>
}
export default Post
I have a product page. I want to use SSG for all products. (about 1000 products).
but each page have related products and suggestion products I want make them with CSR.
this my code:
const initialState = {
relatedProducts: [] as LightGifttDto[],
suggestionsProducts: [] as LightGifttDto[],
}
interface Props {
gift: GiftDto;
}
export default function Gift(props: Props) {
const {gift} = props;
const [pageState, setPageState] = useState(initialState);
//to scroll down of any where
const commentRef = useRef(null)
//to get related products and suggestion products
useEffect(() => {
async function fetchData() {
const [relatedProducts, suggestionsProducts] = await Promise.all([
getRelatedProducts(gift.id),
getSuggestionsProducts(gift.id),
]);
setPageState({
relatedProducts,
suggestionsProducts,
})
}
fetchData();
}, [])
return (
<ShopLayout>
<GiftProvider value={gift}>
<PriceGiftProvider>
<ProductPage commentRef={commentRef}/>
</PriceGiftProvider>
<ProductCarouselSection
products={pageState.relatedProducts}
/>
<ProductComment commentRef={commentRef}/>
<ProductCarouselSection
products={pageState.suggestionsProducts}
/>
</GiftProvider>
</ShopLayout>
);
}
export async function getStaticPaths() {
const giftslugs = await getTopGiftsSlugForServerSideGenerate();
return { paths: giftslugs, fallback: "blocking" };
}
export async function getStaticProps({params}) {
const slug = encodeURI(params.slug);
const gift = await getGiftWithSlug(slug);
return { props: { gift } };
}
But I do not know this way is correct or not for to combine SSG and CSR.
I'm trying to render data from props in React functional component that look like this:
interface TagsComponentProps {
tags: Tag[];
}
const TagsComponent: FC<TagsComponentProps> = (props: TagsComponentProps) => (
<>
{props.tags.length === 0 &&
<LoadingStateComponent />
}
{props.tags.map(tag => {
{ tag.tagId }
{ tag.tagName }
})
}
</>
)
export default TagsComponent;
Within Next.js page that receiving data inside the getStaticProps method. It looks like that:
const IndexPage = ({ tags }: InferGetStaticPropsType<typeof getStaticProps>) => (
<>
<LayoutComponent>
<TagsComponent tags={tags} />
</LayoutComponent>
</>
)
export default IndexPage;
export const getStaticProps = async () => {
const res = await fetch(`${process.env.HOST}/api/tags/read`)
const data = await res.json()
// if (error) {
// return <ErrorComponent errorMessage={'Ошибка загрузки тегов'} />
// }
return {
props: {
tags: data.Items as Tag[]
}
}
}
But nothing is getting rendered at all although I'm receiving data. Probably I'm missing some concept of data fetching for SSR in Next.js.
I guess the issue is .map() is not returning anything in your code here:
{props.tags.map(tag => {
{ tag.tagId }
{ tag.tagName }
})
}
Instead you should try as the following:
{
props.tags.map(tag => (
<>
{ tag.tagId }
{ tag.tagName }
</>
))
}
Also you can do a null check before as props.tags && props.tags.map().
I get the below error when I run "next export". My build is fine but the export fails. I have been following a lot of tutorials but couldn't find a solution. Have I defined my someEntryAsProp correctly?
import Layout from '../components/myLayout.js'
import Link from 'next/link'
import {createClient} from '../helpers/getcontent';
import { type } from 'os';
function getPosts(){
return [
{ id:'hello-nextjs' , title:'Hello Next.js' },
{ id:'learn-nextjs' , title:'Learn Next.js is awesome' },
{ id:'deploy-nextjs' , title:'Deploy apps with Zeit' },
]
}
const PostLink = ({ post }) => (
<li>
<Link as={`/p/${post.id}`} href={`/post?title=${post.title}`}>
<a>{post.title}</a>
</Link>
</li>
)
const Index = () => (
<Layout>
<h1>My Blog</h1>
<p>{someEntryAsProp.fields.title}</p>
<ul>
{ getPosts().map((post) => (
<PostLink key={post.id} post={post}/>
))}
</ul>
</Layout>
);
Index.getInitialProps = async () => {
console.log('> Starting import',);
const client = createClient();
const entries = await client.getEntries({
// some query
content_type:type,
include:2
})
console.log(entries.items[0])
console.log('> Content gotten and written for',)
return { someEntryAsProp: entries.items[0] };
//return {};
};
export default Index
Error:
TypeError: Cannot read property 'someEntryAsProp' of undefined
Can anyone please help me where I am doing wrong?
You need to pass the props to your page-component as an argument:
const Index = ({someEntryAsProp}) => (...)