This question already has an answer here:
How to access route parameter inside getServerSideProps in Next.js?
(1 answer)
Closed 10 months ago.
I have getServerSideProps function to get data from API:
export async function getServerSideProps() {
const res = await fetch(
`https://www.thecocktaildb.com/api/json/v1/1/search.php?s=${queryCocktailName}`
)
const data = await res.json()
return {
props: { data },
}
}
I need to get query in this function, ( /search/queryCocktailName/ ) i tried const {query} = useRouter() but as NextJS say: Hooks can only be called inside of the body of a function component
This component location: search/[id].tsx
This should work:
import { GetServerSidePropsContext } from "next";
export async function getServerSideProps({
params
}: GetServerSidePropsContext<{ id: string }>) {
const res = await fetch(
`https://www.thecocktaildb.com/api/json/v1/1/search.php?s=${params?.id}`
);
const data = await res.json();
return {
props: { data }
};
}
See docs. getServerSideProps gets context object as a first parameter and it contains params field which should contain an id field, because your file is named [id].tsx.
Edit: changed to TypeScript version.
Every getServerSideProps have context, which comprises of req and res.
export async function getServerSideProps({req, res}) {
const { url = "" } = req || {};
//url will have the query of your route like :: url = /search/queryCocktailName/
const res = await fetch(
`https://www.thecocktaildb.com/api/json/v1/1/search.php?s=${queryCocktailName}`
)
const data = await res.json()
return {
props: { data },
}
}
Above code will work for your use-case
Related
I started learning Remix and got to a point where I would like to get some data from APIs. I created a loader function, in routes folder (initially I did this in component, which is wrong), where I fetch my API call:
export async function loader() {
const res = await fetch("https://reqres.in/api/users?page=2");
return json(await res.json());
}
After that I used the data in my component, where needed:
const { data } = useLoaderData();
Now I would like to use another API, but I don't know how properly to do that in the loader function
export async function loader() {
const res = await fetch("https://reqres.in/api/users?page=2");
// second API i would like to use but don't know how :(
const faqRes = await fetch("https://jsonplaceholder.typicode.com/posts");
return json(await res.json());
}
How could I use multiple APIs in Remix?
You can return more data:
export async function loader() {
const res = await fetch("https://reqres.in/api/users?page=2");
const faqRes = await fetch("https://jsonplaceholder.typicode.com/posts");
return json({
res: await res.json(),
faqRes: await faqRes.json()
});
}
Then in your component:
const { res, faqRes } = useLoaderData();
What if you want to wait for 1st API data and pass the response to 2nd API?
e.g.
export async function loader() {
const res = await fetch("https://reqres.in/api/users?page=2");
const faqRes = await fetch(`https://jsonplaceholder.typicode.com/posts/${res.userId}`);
return json({
faqRes: await faqRes.json()
});
}
I am learning how to design API and at the same time how to use next.js API route.
I have set my first route api/property/[propertyId] that returns the specific property detail.
Now I am trying to set a dynamic route for the specific property id in the page folder page/property/[propertyId]. My issue is when I am getting directed on the specific page the data is not there as expected. I am receiving a response for error message.
Can someone point out what I did wrong, please?
pages>api>property>[propertyId]
export default function propertyHandler ({query : {propertyId} } ,res) {
var parser = new xml2js.Parser({explicitArray : false});
const data = fs.readFileSync(path.join(process.cwd(),'listing.xml'))
parser.parseString(data,function (err, results){
results = results.client.secondhandListing.property
const filteredProp = results.filter((property) => property.id === propertyId)
filteredProp.length > 0 ? res.status(200).json(filteredProp[0]) : res.status(404).json({message: `Property with id: ${propertyId} not found.` })
})
}
pages>property>[id].js
export const getDetails = async() => {
const res = await fetch(`${baseUrl}/api/property/[property.Id]}`)
const data = res.json()
return data
}
export async function getServerSideProps({params: { id } }) {
const data = await getDetails(`${baseUrl}/api/property/${id}`)
return {
props: {
propertyDetails: data
}
}
}
I got the answer to my mistake from somewhere else. It was my getdetails function that was wrong.
I have amended it to:
export const getDetails = async(baseUrl)=>{
const res = await fetch(baseUrl)
const data = await res.json()
return data
};
and it worked.
Using nextjs, I have state that contains the users JWT, This needs to be passed into the request in getServerSideProps.
export async function getServerSideProps(ctx) {
const res = await fetch('http://localhost:1337/publics')
const data = await res.json()
const theData = data[ctx.query.id - 1]
return {
props: {data: theData},
}
}
How can i pass the JWT here?
I'm using next.js and the import { useRouter } from 'next/router'.
However on initial load, router.query.id is undefined. It quickly fills in, but that initial load is a killer.
I'm trying to figure out how to do it, and tried:
export async function getStaticProps({ params }) {
// params contains the post `id`.
// If the route is like /posts/1, then params.id is 1
// const res = await fetch(`https://.../posts/${params.id}`)
// const post = await res.json()
console.log(params)
// Pass post data to the page via props
return { props: { params } }
}
but this returns an error:
Error: getStaticPaths is required for dynamic SSG pages and is missing for '/app/d/[id]'.
I can't use getStaticPaths, since [id] is variable and can be any number of things.
So what's the best way to handle this?
I would do smt like this(without staticProps):
function Page(props) {
const router = useRouter();
const { query = {} } = router || {};
const { id = 0 } = query || {};
useEffect(()=> {
if(id) {
(async ()=> {
const res = await fetch(`https://.../posts/${id}`)
const post = await res.json();
})();
}
}, [id]);
}
And this is what official doc. says:
// You also have to define a Post component in the same file (pages/posts/[id].js)
function Post({ post }) {
const router = useRouter()
// If the page is not yet generated, this will be displayed
// initially until getStaticProps() finishes running
if (router.isFallback) {
return <div>Loading...</div>
}
return <h1>Posts are here</h1>;
}
// This also gets called at build time
export async function getStaticProps({ params }) {
// params contains the post `id`.
// If the route is like /posts/1, then params.id is 1
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()
// Pass post data to the page via props
return { props: { post } }
}
UPDATE:
After a bit research, have figure out this solution with staticProps:
export default function Post({ post }) {
return <h1>Post is here</h1>;
}
export async function getStaticPaths() {
return {
paths: [
{ params: { id: '*' } }
],
fallback: true
};
}
export async function getStaticProps(context) {
const res = await fetch(`https://api.icndb.com/jokes/random/${context.params.id}`);
const post = await res.json()
return { props: { post } }
}
I have set up exportPathMap but I get an empty object when exporting getStaticProps from my component. I don't understand how I'm supposed to access it?
// next.config.js
exportPathMap: async function (
defaultMapPath,
{ dev, dir, outDir, distDir, buildId }
) {
const paths = {}
const response = await fetch(...)
const data = await response.json()
data.forEach((item) => {
paths[`/item/${item.id}`] = {
page: '/itemPage',
query: {
item,
},
}
})
return paths
},
And
// itemPage.js
...
export async function getStaticProps(props) {
console.log('props', props) // returns "props {}""
return {
props: props
}
}
...
It's difficult to find it specifically stated in the documentation right now, but here are your options.
OPTION 1
Use getStaticPaths and getStaticProps like so (from "with-static-export" in the nextJS examples)
// [id].js post file
export async function getStaticPaths() {
const response = await fetch(
'https://jsonplaceholder.typicode.com/posts?_page=1'
)
const postList = await response.json()
return {
paths: postList.map(post => {
return {
params: {
id: `${post.id}`,
},
}
}),
fallback: false,
}
}
export async function getStaticProps({ params }) {
// fetch single post detail
const response = await fetch(
`https://jsonplaceholder.typicode.com/posts/${params.id}`
)
const post = await response.json()
return {
props: post,
}
}
OPTION 2
Use exportPathMap AND getInitialProps
// item.js
...
Page.getInitialProps = function (context) {
return context.query.item
}
// next.config.js
module.exports = {
// ...Same as in your question...
}
Both will allow you to have static optimization. With Option 1, you need not export, next build is sufficient. For Option 2 you will need to run next export
From: https://nextjs.org/docs/advanced-features/static-html-export
If your pages don't have getInitialProps you may not need next export at all; next build is already enough thanks to Automatic Static Optimization.
Another note: You can use both methods inside a single project.