Create dynamic routes by id from Next JS pages api - javascript

I have a page with a list of objects called stories that displays all my stories in an array. I also have a detail page with displays an individual story.
I want to click on a link on any given story on the list, then it will navigate me to the individual story. I want to use _id as my dynamic part of the URL, as shown in the GraphQL below.
My Graphql
export const listAllStories = () => {
const query = gql`
query StoryEntries($size: Int) {
storyEntries(_size: $size) {
data {
_id
_ts
name
premises{
data{
_id
content
}
}
createdAt
}
}
}
`
return graphQLClient
.request(query, { size: 999 })
.then(({ storyEntries: { data } }) => data)
}
IN MY PAGES API I HAVE
export default async function handler(req, res) {
const handlers = {
GET: async () => {
const storyEntries = await listAllStories()
res.json(storyEntries)
},
}
if (!handlers[req.method]) {
return res.status(405).end()
}
await handlers[req.method]()
}
ON THE STORY LIST PAGE I HAVE
const ENTRIES_PATH = '/api/entries/allStories'
const useEntriesFlow = ({ initialEntries }) => {
const { data: entries } = useSWR(ENTRIES_PATH, {
initialData: initialEntries,
})
const EntryItem = ({ entry }) => (
<>
{entries?.map((entry) => (
{entry.name}
<Link href="/story/[storyId]" as={`/story/${entry._id}`}>
<a>Go</a>
</Link>
))}
</>
)
export const getStaticProps = async () => ({
props: {
initialEntries: await listAllStories(),
},
revalidate: 1,
})
This is fine and works.
**AND THEN ON THE DETAIL PAGE FOR EACH INDIVIDUAL STORY [storyId].js I HAVE **
export default function Story({story}) {
const router = useRouter()
const storyId = router.query.storyId
return(
<>
<h5>hello {story._id}</h5>
</>
)
}
export const getStaticPaths = async () => {
const res = await fetch(`${server}/api/entries/allStories/`);
const { data } = await res.json();
const paths = data.map(story => {
return {
params: { id: story._id.toString() }
}
// trying to get the _id from each story
})
return {
paths,
fallback: false
}
}
export const getStaticProps = async (context) => {
const { storyId } = context.query; // Your dynamic page is [storyId].js
const server = "http://localhost:3000";
const res = await fetch(`${server}/api/entries/allStories/${storyId}`);
// trying to get the params._id from each story
console.log(res)
const { data } = await res.json();
return {
props: { story: data }
}
}
ERROR
TypeError: Cannot read properties of undefined (reading 'map')
QUESTION
All I want to do is click on any story link, then it takes me to the details page, via the _id. I have tried a few things but I'm doing something (or some things) wrong.
Any help will be greatly appreciated.
EDIT AFTER. ERROR I'M GETTING. I'm not able to map my results on getStaticPaths

export const getStaticProps = async (context) => {
const { storyId } = context.query; // Your dynamic page is [storyId].js
const server = "YOUR SERVER VARIABLE";
const res = await fetch(`${server}/api/entries/allStories/${storyId}`);
// trying to get the params._id from each story
const { data } = await res.json();
return {
props: { story: data }
}
}

uncomment
const router = useRouter()
const storyId = router.query.storyId

// some helpful links
// https://nextjs.org/docs/basic-features/data-fetching#the-paths-key-required
// https://stackoverflow.com/questions/65783199/error-getstaticpaths-is-required-for-dynamic-ssg-pages-and-is-missing-for-xxx
export const getStaticPaths = async () => {
const server = "http://localhost:3000";
const data = await fetch(`${server}/api/entries/allStories/`).then(res => res.json() )
const paths = data.map(({_id}) => ({
params: { storyId: _id },
}))
return {
paths,
fallback: false
}
}
export const getStaticProps = async (context) => {
const storyId = context.params.storyId; // Your dynamic page is [storyId].js
const server = "http://localhost:3000";
// const res = await fetch(`${server}/api/entries/allStories/${storyId}`);
// trying to get the params._id from each story
// single api call (here)
const res = await fetch(`${server}/api/entries/allStories/`);
// removing const { data } because the data will be returned when calling res.json()
const data = await res.json();
// instead of the calling the single api (just a fix not recommended to access [0] directly )
return {
props: { story: data.filter(story => story._id === storyId)[0] }
}
}

Related

getStaticProps showing wrong/previous data in Reactjs

I am working on Rectjs,I am using nextjs, I created "[slug.js]" for dynamic routes,But its showing previous data instead of current data(fetching from database via axios),I checked in console.log,and in console showing old data not current,where i am wrong ?Here is my current code
const Post = function ({post}) {
useEffect(() => {
// showing old record/title instead of current
console.log(`Found Post title : ${post.title}`);
}, []);
};
export const getStaticProps = async ({ params }) => {
const { data } = await axios.get(
`https://diggdevelopment.com/blackstallion_new/api/getblogbyuserid/${params.slug}`
);
const post = data;
console.log('dat is' + post);
return {
props: {
post,
},
};
};
export const getStaticPaths = async () => {
const { data } = await axios.get(
'http://diggdevelopment.com/blackstallion_new/api/blogscopy'
);
const posts = data.slice(0, 10);
const paths = posts.map((post) => ({ params: { slug: post.id.toString() } }));
return {
paths,
fallback: true,
};
};

can't render fetched api data on my nextjs project

on this nextjs project i'm fetching data from an api and it's logging successfully. but i just can't seem to render the response (from the handleSubmit const) on my main jsx return. i try it as {cart.categoryTitle} and i got no error, but also no render on my app. am i doing something wrong? thanks!
import { useEffect, useState } from "react";
const Lista = () => {
const [categoryTitle, setCategoryTitle] = useState<any>();
const [cart, setCart] = useState([])
interface Data {
id: number;
title: string;
}
useEffect(() => {
handleCategoryData();
}, []);
async function handleCategoryData() {
const response = await fetch("/api/category");
const categoryTitle = await response.json();
setCategoryTitle(categoryTitle);
}
const handleSubmit = async (event: any) => {
event.preventDefault();
const categoryTitle = event.target[0].value;
const sub = event.target[1].value;
const name = [event.target[2].value];
const type = event.target[3].value == "Unidade" ? "unit" : "kg";
const price = event.target[4].value;
const counter = event.target[5].value;
//const img = event.target[6].value;
const res = await fetch("../api/list", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
products: [
{
categoryTitle,
sub,
name,
type,
price,
quantity,
},
],
}),
});
const response = await res.json();
console.log(response);
// return JSON.stringify(response);
setCart(response)
};
if (!categoryTitle) return <p>Loading</p>;
if (!sub) return <p>Loading</p>;
if (!productResponse) return <p>Loading</p>;
return (
<>
<section>
<div className="listsContainer">
<div className="cartContainer">
<div className="listText">
<p>Lista</p>
<p>{cart.categoryTitle}</p>
<p>0 categorias / 0 itens</p>
</div>
</div>
What does the response look like? Is it an object that has categoryTitle property? It may be the case that there’s no categoryTitle in the response object. Your cart state is being initialize as an array so maybe you are expecting the response to be an array as well?

Next.js Dynamic Path - Can't get context.params query

I am trying to set up a dynamic page in Next.js with getStaticPaths(). I have it 90% of the way there, but I can't get the getStaticProps() function to reference the URL query so that it loads the proper info.
My code is:
//Get Static Paths
export async function getStaticPaths() {
const paths = await (
await youtube.get("search?")
).data.items.map((video: any) => {
const id = video.id.videoId;
return { params: { id } };
});
return {
paths: paths.map((path: any) => path),
fallback: false,
};
}
//Get Static Props
export async function getStaticProps(context: any) {
const { query = "" } = context.params.query;
const videos = await (await youtube.get("search?")).data.items;
const video = videos.find((vid: any) => {
return vid.id.videoId === query;
});
return {
props: {
video,
},
revalidate: 10,
};
}
I am receiving the error:
Error: Error serializing `.video` returned from `getStaticProps` in "/media/videos/[id]".
Reason: `undefined` cannot be serialized as JSON. Please use `null` or omit this value.
If I replace the 'query' variable in the getStaticProps() function with the actual ID of the video I am trying to load, everything goes through fine and the page loads. But then this is not dynamic, and is not using the url query to match with the proper video like I want.
Here is the working, non-dynamic code with a manually typed in ID to force a match.
//Get Static Props
export async function getStaticProps(context: any) {
// It's important to default the slug so that it doesn't return "undefined"
const { query = "" } = context.params;
const videos = await (await youtube.get("search?")).data.items;
const video = videos.find((vid: any) => {
return vid.id.videoId === "_TACZtT1irI";
});
return {
props: {
video,
},
revalidate: 10,
};
}
How can I make sure that the 'video' variable is accessing the url query? It should be grabbing it with context.params, but that is not working, what am I doing wrong?
I figured it out. This is working.
//Get Static Props
export async function getStaticProps(context: any) {
// It's important to default the slug so that it doesn't return "undefined"
const { query = "" } = context.params;
const videos = await (await youtube.get("search?")).data.items;
const video = videos.find((vid: any) => {
return vid.id.videoId === context.params.id;
});
return {
props: {
video,
},
revalidate: 10,
};
}

Cannot retrieve Title from Strapi

I have collection type called posts and it has the following values:
Now to get the api I have a file in my lib folder which contains the following code:
export async function getPosts() {
var api_base_url = process.env.API_BASE_URL;
const response = await fetch(api_base_url + "/posts");
const posts = await response.json();
return posts;
}
export async function getPost(postId) {
var api_base_url = process.env.API_BASE_URL;
const response = await fetch(api_base_url + "/posts/" + postId);
const post = await response.json();
return post;
}
export async function getPostFromTitle(postTitle, lang) {
var api_base_url = process.env.API_BASE_URL;
const response = await fetch(api_base_url + "/posts");
const posts = await response.json();
var postObject = {};
posts.forEach(post => {
if (post['Title (' + lang.toUpperCase() + ')'] == postTitle) {
postObject = post;
}
});
return postObject;
}
Now to display this I have used the following code:
import { getPosts, getPostFromTitle } from '../lib/apiGet'
export async function getStaticProps() {
const allPosts = JSON.parse(JSON.stringify(await getPosts()));
const postsTitle = JSON.parse(JSON.stringify(await getPostFromTitle(postTitle, lang)));
//Parse and Stringify done since nextJs was having weird errors accepting the standard json from API
return {
props: {
allPosts,
postsTitle
}
}
}
export default function Home({ allPosts, postsTitle }) {
return (
<div>
<body>
<ul>
{allPosts.map(post => (
<h1><u>
{console.log(post.id)}
{post.id}
</u>
</h1>
))}
</ul>
<ul>
{postsTitle.map((postTitle, lang) => (
<h1><u>
{console.log(postTitle.Title)}
{postTitle.Title}
</u>
</h1>
))}
</ul>
</body>
</div>
);
}
I am able to get the id correctly, but when I go to print the Title I get this error.
So how do I retrieve my title correctly?
I believe the issue might be in your frontend function;
export async function getPostFromTitle(postTitle, lang) {
var api_base_url = process.env.API_BASE_URL;
const response = await fetch(api_base_url + "/posts");
const posts = await response.json();
var postObject = {};
posts.forEach(post => {
if (post['Title (' + lang.toUpperCase() + ')'] == postTitle) {
postObject = post;
}
});
return postObject;
}
It might not yield any post - i would debug the function. Is the "posts" const containing valid objects? does the return value seem correct or is it undefined?
Generally speaking, it would be much simpler for you to re-write the filter part of your function (everything beyond await response.json();) to use the js filter function.
Something like;
return posts.filter(post => post['...'].includes(postTitle));

Not getting any data from API

import axios from 'axios';
const url = 'https://covid19.mathdro.id/api';
export const fetchData = async () => {
try {
const { data: { confirmed, recovered, deaths, lastUpdate} } = await axios.get(url);
return {confirmed, recovered, deaths, lastUpdate};
} catch (error) {
}
}
export const fetchDailyData = async()=> {
try{
const data = await axios.get('${url}/daily');
console.log("DATA",data);
const modifiedData = data.map((dailyData) => ({
confirmed: dailyData.confirmed.total,
deaths: dailyData.deaths.total,
date: dailyData.reportDate,
}));
return modifiedData;
} catch(error){
console.log("DATA NOT FOUND");
var r = []
return r
}
}
Here I'mt trying to get data from this API: https://covid19.mathdro.id/api/daily
But Whenever I'm trying to call fetchDailyData , I'm only getting "DATA NOT FOUND" on the console
You used ' instead of ` (near below escape button) to use string templates:
const data = await axios.get(`${url}/daily`);
Besides the ' wrong syntax, the data.map will also throw an error: map is not a function, because you are trying to map the response and not the response.data.
You should do something like that:
const data = await axios.get('${url}/daily');
To:
const response = await axios.get(`${url}/daily`);
And your map:
const modifiedData = data.map((dailyData) => ({
To:
const modifiedData = response.data.map((dailyData) => ({

Categories