This question already has an answer here:
Next js nested dynamic routes: data fetching via getstaticprops with shared data between routes
(1 answer)
Closed last year.
im fetching a huge json data from an external API inside my getstaticprops. this data will then be divided into parts to be send to other static pages (hundreds of pages) as props.
// page1.tsx
const page1 = ({ page1Data }) => {
...
}
const getStaticProps: GetStaticProps = async () => {
const res = await fetch('https://hugedata')
const jsonData = await res.json()
const { page1Data, page2Data, page300Data, ...allData } = jsonData
return { props: { page1Data } }
}
i only know how to send the staticprops data to the component inside the file like this.
is there a way send these data to other static pages/routes ? (e.g. to page2.tsx)
It's not really possible to send data between pages. But you can see the methods described here.
I suggest you really check router and inspect data inside it, you can find a lot of info about data on the page.
P.S. As I see, you are trying to get a lot of data and you need to use pagination and split it to the parts, you can use this lib
Related
I am currently trying to build a Reddit client with React. For those of you that are not familiar with Reddit, it's basically a social network that consists of thousands of communities or "subreddits" created by users. Each subreddit has posts that can contain text, images, videos or links, and can be found under the URL reddit.com/r/<subreddit_name>. Reddit's public API is very simple in that you can just add .json to this URL to get a JSON response containing the posts. Specifically, the relevant data lies at response.data.children, which is an array of objects representing the posts.
Reddit doesn't have pagination in that I can just call the API and pass something like ?page=42 as a query string. Instead, I have to pass a query string containing the value of the response.data.after property of the previous response, which is basically the ID of the last post of that response, so that Reddit can now send me posts starting with the next one after that.
Currently, my custom hook to call the API looks like this:
function usePosts(community) {
const [fetching, setFetching] = useState(false);
const [error, setError] = useState(null);
const [posts, setPosts] = useState([]);
useEffect(() => {
setFetching(true);
getPosts(community)
.then(value => {
setError(null);
setPosts(value.data.children.map(value => value.data));
})
.catch(error => setError(error))
.finally(() => setFetching(false));
}, [community]);
return [fetching, error, posts];
}
The getPosts() method simply fetches the data from the API and does some error handling in case the response is not okay.
Now on to my question: How can I best implement it so that I can not only call this hook to load the first posts (which I am already doing), but also have some way of storing the after property, and then call the hook again when I want the next few posts to be appended to the posts array? Or do I need another hook? And do I have to return after as well if I want to store it, since I am mapping the response to be only the post data? How would you solve this?
Greetings to everyone,
I have just started to learn NodeJS and have been experimenting on API routes in NextJS as its easy to setup and see what's actually going on, So I know how to make a basic get request but I'm interested in something a little complex.
So I'm trying to build an API route that can be filleted by page number, so for example api/pages/1 would return page 1 and so on.
so this is my file in /api/game.js
export default async function handler(req,res) {
const response = await fetch('https://exampleapi.com/pages/?sort=&page=1&per_page=50')
const jsonData = await response.json();
res.status(200).json(jsonData);
}
Now this works obviously but I want to know how I can make dynamic routes for all the pages. Since I'm using an external API I'm not sure how many pages exist at any moment.
So far I have created another folder and called the file [gamepage].js, I'm not sure how I would manipulate the fetch call in the game.js file in here.
export default async function handler(req, res) {
const { pno } = req.query
console.log(pro)
const response = await fetch(`https://exampleapi.com/pages/?sort=&page=${pno}&per_page=50`)
const jsonData = await response.json();
res.status(200).json(jsonData);
}
Sorry if the question is too beginner level, I'm just getting started with backend JS.
I got it to work, I was just missing the gamepage from req.query
const { pno } = req.query.gamepage
this did it.
We are currently working on a Nextjs project which includes a number of dynamic pages. We have come to a stage where we are defining the dynamic paths using getStaticProps and getStaticPaths. So far we managed to define 404 pages in dynamic pages with a similar structure to the below:
export async function getStaticProps(context) {
const { id } = context.params
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
const user = await response.json()
return {
props: { user },
notFound: Object.keys(user).length === 0
}
}
export function getStaticPaths() {
return {
paths: [],
fallback: 'blocking'
}
}
Using version 10's notFound value and fallback: blocking allows us to have the page return a 404 status code (for some reason fallback: true returns a 200 status code).
The issue we currently have is to display a 404 page to pages that depend on user data such as username or user locale. One way we thought we could solve this is by having those pages as Server Side generated rather than Static Site generated by using getServerSideProps:
export async function getServerSideProps(context) {
const userId = getCookie('user_id')
const response = await fetch(`___/checkUserAccess/${userId}`)
const access = await response.json()
return {
props: { ... },
notFound: !access.userAllowed
}
}
I suppose I am answering my own question here as going for Server Side for these pages to show 404 pages based on user data seems logical. However the concern is the impact it may have on the website as a whole. These pages could easily end up being hundreds of pages.
Should we be concerned about this? Or maybe there's another way to go about solving this?
This question already has an answer here:
Fetch error when building Next.js static website in production
(1 answer)
Closed 11 months ago.
I am using Next.js with the Vercel deployment workflow, I am following this guide to try and setup page generation at buildtime. The specific section shows the following example to generate pages based on an external API's response:
// This function gets called at build time
export async function getStaticPaths() {
// Call an external API endpoint to get posts
const res = await fetch('https://.../posts')
const posts = await res.json()
// Get the paths we want to pre-render based on posts
const paths = posts.map(post => ({
params: { id: post.id },
}))
// We'll pre-render only these paths at build time.
// { fallback: false } means other routes should 404.
return { paths, fallback: false }
}
// 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 } }
}
I want to do this exactly, however I wrote my API as a Node.js serverless function within the same code repository, it is not an external api.
I tried to do the following to call on my api:
// This function gets called at build time
export async function getStaticPaths() {
const res = await fetch('/api/get-designs');
const designs = await res.json();
// Get the paths we want to pre-render based on posts
const paths = designs.map(design => ({
params: { id: design.id },
}))
return {
// Only posts returned by api are generated at build time
paths: paths,
// Enable statically generating additional pages
fallback: true,
}
}
However I get an error that the fetch api url must be absolute. Because of the way Vercel deploys, I won't always have the same deployment URL, so I don't think I can just use a hardcoded value here. Also, I am suspecting that because this function runs at buildtime, that my function is not running yet, therefore can not be called. I am still trying to wrap my head around this Next.js statically generated site workflow, but basically I am confused because they seem to encourage using serverless functions, and this getStaticPaths method for page generation, but they don't seem to work together unless I am missing something.
Is there a way I can run my api to get these results at build time? Any guidance would be much appreciated!
Thanks!
In this case, we can extract the server logic into a function and that function can be used directly inside your api route file. So, for CR we can use /api/whateverRoute and inside getStaticPaths we can use that function itself directly.
I have several pages that reference the same node in firestore, each pulling different segments from the firestore node. For example, a summary page might pull through album title, date, genre and image, whilst another page might pull through just the title, artist and record label. A couple of questions:
Is it possible to turn one of the firestore queries into a service?
If so, does that mean the data is only read once whilst navigating across different pages (angular components) that use the same service?
Will the query only run again when data is modified in firestore through the observable? ("return Observable.create(observer => {" )
I have tried a service with the code below. However, the issue observed is that on page refresh, the data isn't present. It is however present whilst navigating through the site. I believe this is because my page is running before the observable is returned. Is there a way to wrap up the query as an observable?
Any assistance would be greatly appreciated.
getAlbumData() {
this.albumDoc = this.afs.doc(`albums/${this.albumId}`);
this.album = this.albumDoc.snapshotChanges();
this.album.subscribe((value) => {
// The returned Data
const data = value.payload.data();
// Firebase Reference
var storage = firebase.storage();
// If album cover exists
if (data.project_signature != undefined) {
// Get the Image URL
var image = data.album_cover_image;
// Create an image reference to the storage location
var imagePathReference = storage.ref().child(image);
// Get the download URL and set the local variable to the result (url)
imagePathReference.getDownloadURL().then((url) => {
this.album_cover = url;
});
}
});
}
When I build my observables, I try to use operators as much as I can until I get the data I want to display in my UI.
You don't want to implement too much code in the subscribe method because you break the reactive paradigm by doing so.
Instead, extract you data in your observable and display it in your template.
Don't forget to use the async pipe in your template to display your data when it gets fetched by your application.
I would do something like this:
// In AlbumService
getAlbumCover(albumId: string) {
const albumDoc = this.afs.doc(`albums/${albumId}`);
const album_cover$ = this.albumDoc.snapshotChanges().pipe(
// get the album data from firestore request
map(data => {
return {
id: data.payload.id,
...data.payload.data()
};
}),
// emits data only if it contains a defined project_signature
filter(album => album.project_signature),
// prepare the imagePath and get the album cover from the promise
mergeMap(album => {
const storage = firebase.storage();
const image = album.album_cover_image;
const imagePathReference = storage.ref().child(image);
return imagePathReference.getDownloadURL();
})
);
return album_cover$;
}
By doing so, when your data is updated in firestore, it will be fetched automatically by your application since you use an observable.
In your component, in the onInit() method after getting your album id from the url:
this.album_cover$ = this.albumService.getAlbumCover(albumId);
Finally, in my template, I would do :
<div>{{album_cover$ | async}}</div>