How to pass a parameter in getStaticProps in Nextjs - javascript

I just want to ask how can I call an API when a user "click the search button" and display the appropriate result in NextJS. Thank you!
This is the API I'm using https://www.themealdb.com/api/json/v1/1/search.php?s=Steak and note the "Steak" word is the food I want to see.
Here is my url in development mode http://localhost:3000/search/steak/.
I want to pass the "steak" in getStaticProps and pass the result of getStaticProps in my component.
export const getStaticProps = async () => {
const res = await axios.get(
'https://www.themealdb.com/api/json/v1/1/search.php?s=Steak'
);
return {
props: {
meals: res.data,
},
};
};

I think you can't do it. GetStaticProps render the page at build time, so you can't render a page based on user request.
I suggest you to read this docs, section 'when I should use GetStaticProps'.
You can use react state, or GetServerSideProps (read the same docs).
You can also static render a bunch of page using GetStaticPath and pass, for example, the 10 most searched foods.

You can do this with getStaticPaths if you are using dynamic routes.
You can use search/[slug].js as a dynamic route in your file based routing.
Then, in [slug].js you would have something like:
export default function Page({ response }) {
return <div>{JSON.stringify(response)})</div>
}
// get all the possible paths for the individual ingredients
export async function getStaticPaths() {
const data = await axios.get(
'www.themealdb.com/api/json/v1/1/list.php?i=list'
);
return {
paths: data.meals.map((ingredient) => ({
params: { slug: ingredient.strIngredient.toString().toLowerCase. },
})),
fallback: false, // can also be true or 'blocking'
}
}
export async function getStaticProps({ params }) {
const { slug } = params
const response = await axios.get(
`https://www.themealdb.com/api/json/v1/1/search.php?s=${slug}`
);
return {
props: {
response
},
}
}

Related

How do I get my layout component to remain static in Next13 app folder

I am trying to create a layout component that fetches its own data, I have tried adding the cache: 'force-cache' to the fetch but every time I update my CMS content and refresh my page the new content is loaded. Here is an example of my code:
const getLayoutData = async () => {
const response = await fetch(
`https://cdn.contentful.com/spaces/${
process.env.CONTENTFUL_SPACE_ID
}/environments/${
process.env.CONTENTFUL_ENVIRONMENT || "master"
}/entries/${fieldId}?access_token=${process.env.CONTENTFUL_ACCESS_TOKEN}`,
{
cache: "force-cache",
}
);
const {entryTitle, ...headerData} = await response.json();
return { headerData };
}
export default async function Layout() {
const data = await getLayoutData();
...
You can use the getStaticProps() function to fetch data at build time and make it available to your component as a prop. This way, the data will be pre-rendered on the server and will not change when the user refreshes the page:
import getLayoutData from './getLayoutData';
export async function getStaticProps() {
const data = await getLayoutData();
return { props: { data } };
}
export default function Layout({ data }) {
// Use data in your component
...
}
Alternatively you could use getServerSideProps(), it runs on the server at request time instead of build time. I would recommend that if you have dynamic data that changes frequently:
import getLayoutData from './getLayoutData';
export async function getServerSideProps(context) {
const data = await getLayoutData();
return { props: { data } };
}
export default function Layout({ data }) {
// Use data in your component
...
}
By default, Next.js automatically does static fetches. This means that the data will be fetched at build time, cached, and reused on each request. As a developer, you have control over how the static data is cached and revalidated.
Refer to the docs - https://beta.nextjs.org/docs/data-fetching/fundamentals
Also, this will work in production mode. So, make sure you are using next build && next start and not next dev.
In case you are fetching data from same URL anywhere else, the cache might be getting updated. As Next.js also does request deduplication built into the fetch function itself.

nextjs getServerSideProps vs API

I'm trying to understand the main difference between getServerSideProps and just using useSWR inside of the page component. If I run something like this inside getServerSideProps:
export const getServerSideProps = async () => {
try {
const palettes = []
const docRef = query(collection(db, 'palettes'), orderBy('likes', 'desc'), limit(16))
const docData = await getDocs(docRef)
docData.forEach((doc) => {
palettes.push(doc.data())
})
if (!docData) {
return {
props: {
data: { error: 'Failed to load palettes. Please refresh the page.'}
}
}
} else {
return {
props: {
data: { palettes }
}
}
}
} catch (e) {
console.log('error:', e)
}
}
It will run at build time and then on each request by the user when viewing/navigating to the page?
Then what would be the difference from just using useSWR or another API fetcher like:
export default function PaletteSlugs({ slug }) {
const { data, error } = useSWR(`/api/palette/${slug}`, fetcher)
return (
{data}
)
}
Also could this affect how many request/reads will happen on the database?
Simply, using getServerSideProps will get the API data on the Node.js server, while the HTML page will be completely populated by Node.js on the server. If you try to open the page source in the browser you will see all data already exists in the page source, this will be better for SEO.
But with useSWR will get the data on the client-side like normal fetch and the data will be populated on the client-side.

Sveltekit Error: `page` in `load` functions has been replaced by `url` and `params`

I am trying to display my date from GraphCMS in my blog application. I receive this error when I go to my single post link (http://localhost:3000/posts/union-types-and-sortable-relations)
"
page in load functions has been replaced by url and params
Error: page in load functions has been replaced by url and params
"
Here is my code
<script context='module'>
export const load = async ({fetch, page: {params}}) => {
const {slug} = params
const res = await fetch(`/posts/${slug}.json`)
if(res.ok) {
const {post} = await res.json()
return {
props: {post},
}
}
}
</script>
<script>
export let post
</script>
<svelte:head>
<title>Emrah's Blog | Welcome</title>
</svelte:head>
<pre>{JSON.stringify(post, null, 2)}</pre>
Can you please help. Thanks
Try using params instead of page: params, though the latter still works in Sveltekit 278 (which I'm using).
Besides, I'm curious to know what makes you prefer this method to querying GraphCMS for your single post. I do it like this:
import {client} from '$lib/js/graphql-client'
import {projectQuery} from '$lib/js/graphql-queries'
export const load = async ({ params }) => {
const {slug} = params
const variables = {slug}
const {project} = await client.request(projectQuery, variables)
return {
props: {
project
}
}
}
Yes, this has been changed a while ago, now the different parts of what used to be page are passed directly into the load function:
export async function load({ fetch, page }) {
const { params, url } = page
}
export async function load({ fetch, params, url }) {
}
Something else to consider is that now there are page endpoints, if your file is [slug].svelte you can make a file [slug].js and add the following:
export async function get({ params }) {
const { slug } = params;
const post = {}; // add the code to fetch from GraphCMS here
return {
status: 200,
body: {
post
}
}
}
With this you can remove the load function and make your code simpler (especially because you technically already have all this code in your /posts/[slug].json.js file.
<script context='module'>
export async function load({ fetch, params}){
let id = params.users
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
const user = await response.json()
if(response.ok){
return {props:{user}}
}
return {
status: response.status,
error : new Error(" sorry no user found")
}
}
export let user

getStaticPaths - data.map is not a function

I am using Strapi with Next.js for my blog project
I am trying to make dynamic pages by using [id].js inside pages/posts/[id].js
But, the problem is when I try to map through the API of Strapi inside getStaticPaths() it gives me an error with data.map is not defined
Note:- I am using NextJS V12.0.8 with Strapi V4.0.4
Below is my code
export async function getStaticPaths() {
const postsRes = await axios.get("http://localhost:1337/api/posts?populate=image");
const paths = postsRes.map((post) => {
return { params: {id: post.id.toString()} }
});
// const paths = { params: {id: '1' } }
return {
paths,
fallback: false
}
}
Complete [id].js Page Code Link - https://pastebin.com/SnzLirys
Error Screenshot - https://prnt.sc/26ha6z5
apparently you need to set up a context to use axios inside that function, or you can try to format the axios response to json.stringfy and then use json.parse in it. or just use fetch.
in case you are using next api folder, don't call fetch or axios here, just make the query as if you were in node
export async function getStaticPaths() {
const get = await fetch("url")
const data = await get.json()
data.map(item => console.log(item))
const paths = data.map((post) => {
return { params: {id: post.id.toString()} }
});
// const paths = { params: {id: '1' } }
return {
paths,
fallback: false
}
}

getStaticProps Does not return any data to the pages on Next.JS

I'm trying to fetch a data from my hosted database. The database itself are working (I have checked it from the swagger app) but no data is shown when it is called from API form.
import React from 'react';
export const getStaticPaths = async () => {
const res = await fetch('https://[server]/course');
const data = await res.json();
const paths = data.result.map(course => {
return {
params: { id: course._id.toString() }
}
})
return {
paths,
fallback: false
}
}
export const getStaticProps = async (context) => {
const id = context.params.id;
const res = await fetch('https://[server]/course/' + id);
const data = await res.json();
return {
props: { course: data }
}
}
const Details = ({ course }) => {
return (
<div>
<h1> { course.course_name } </h1>
<h1>a</h1>
</div>
);
}
export default Details;
The code is in the pages folder. I followed a tutorial on youtube from "netninja" and when I tried it on his code it works. I read somewhere that it won't work on components but I already put it on the pages but it still does not return anything.
Is there anything I can do ?
I got the answer. After checking console.log on the data. Looks like the data is on another array which is called result. so i needed to call the data from course.result.course_name. So the Answer is just to check console.log every once in a while. Shout out to juliomalves for pointing that out

Categories

Resources