Failing to fetch dynamic data from firestore using getStaticPaths in nextjs - javascript

When I fetch data from firebase firestore using getStaticProps, it works perfectly but when I try implementing the logic of getting the details of each single item using getStaticPaths, I fail and get a 404 page. This is how my [id].js code looks like currently.
import React from 'react'
import { db } from '#/Firebase';
import {collection, getDoc} from "firebase/firestore";
const reference = collection(db, "abantu");
export const getStaticPaths= async () => {
const umuntu = await getDoc(reference);
const paths = umuntu.docs.map(doc => {
return {
params: { id: doc.id }
}
})
return {
paths,
fallback: false
}
}
export const getStaticProps = async (context) => {
const id = context.params.id;
const data = await getDoc(reference) + id;
return {
props: {
umuntu: data
}
}
}
function Details({umuntu}) {
return (
<div>
<h1>{umuntu.ibizo}</h1>
</div>
)
}
export default Details
I dont quite get where my logic is going wrong but where could I be going wrong?.

For finding the right page props for each of the paths that you generate from the database in the getStaticPaths function, you should be able to find each of the pages information based on the id field you are getting from each path, see it here:
export const getStaticProps = async (context) => {
const id = context.params.id;
const umuntu = await getDoc(reference);
const data = umuntu.docs.find((pageData) => pageData.id === id); // this will find the right page based on the id passed via page path
return {
props: {
data
},
};
};
function Details({ data }) {
return (
<div>
<h1>{data.ibizo}</h1>
</div>
);
}
export default Details;

Related

Nextjs getStaticProps failing to read firebase firestore data

I am trying to read my data from firestore using getStaticProps, but somehow, it is rendering an empty page. I must say, when I use useEffect, the data renders, but the moment I change it to getStaticProps, it returns an empty page. This is how the code looks like at the moment
import { db } from '#/Firebase';
import { collection, getDocs } from "firebase/firestore";
const reference = collection(db, "students");
function Card(props) {
const { studentsData } = props
return (
<div>
<p>This is just a test</p>
{studentsData && studentsData.map(students => (
<div className="l">
<p>{students.name}</p>
</div>
))}
</div>
)
}
export const getStaticProps = async () => {
const students = await getDocs(reference);
const studentsData = students.docs.map(doc => ({id: doc.id, ...doc.data() }))
console.log(studentsData);
return {
props: { studentsData }
}
}
export default Card
I have followed the docs and multiple tutorial blogs online, but it is now working for me. How and where could I be going wrong?

Destructuring specific data from a react component

I would like to be able to make both data.account and data.assets accessbile individually. The idea is to be able to insert this component into a page where I can say something like:
import UserAccounts from '...';
"This user (**data.account**) owns this number (**data.assets**) of assets".
The following is the component code:
function UserAccounts() {
const [accounts, setAccounts] = useState();
useEffect(() => {
async function fetchData() {
const res = await fetch(
'https://proton.api.atomicassets.io/atomicassets/v1/accounts?limit=10'
);
const { data } = await res.json();
setAccounts(data);
}
fetchData();
}, []);
if (!accounts) {
return (
<div>
<Spinner />
</div>
);
}
const account = accounts.map((data) => {
return <>{(data.account, data.assets)}</>;
});
return <></>;
}
export default UserAccounts;
the way that it is now, it's pulling the accounts from the api. The problem is that it's not set to return anything. I'm trying to figure out how I can decide which to return based on what I need (data.account or data.assets

Possible async problem with firebase get request

I have a function useVenue that returns venue data from a call to firebase:
import { useState,useEffect } from 'react'
import { firebase } from './firebaseConfig'
export function useVenues (){
const [venues, setVenues] = useState([]);
useEffect(() => {
const venueArray = [];
const getAllVenues = async () => {
await firebase
.firestore()
.collection("venues")
.get()
.then((snapshot) => {
snapshot.forEach((venue) => {
venueArray.push(venue);
});
setVenues(venueArray);
});
};
getAllVenues();
}, []);
const [...venueData] = venues.map((venue) => {
const {
name,
photoUrl,
averageRating,
numRatings,
type,
address,
phone,
website,
reviews } = venue.data();
return ({
name: name,
photoUrl: photoUrl,
averageRating: averageRating,
numRatings: numRatings,
type: type,
id: venue.id,
reviews:reviews,
address:address,
phone:phone,
website:website
})
});
return {venueData}
};
This function is exported to venues.js where the venue data is destructured out and pass as props to MidSection.js:
venues.js
import { useParams } from 'react-router-dom';
import { useVenues } from '../useVenue';
import Header from '../components/Header'
import VenueDetails from '../components/venue-page/VenueDetails'
import MidSection from '../components/venue-page/MidSection';
import ReviewSection from '../components/venue-page/ReviewSection';
const Venue = () => {
let {id} = useParams()
const { venueData } = useVenues()
const filteredVenue = venueData.filter(item => {
return item.id === id
})
return(
<div>
<Header/>
<VenueDetails filteredVenue = {filteredVenue}/>
<MidSection filteredVenue = {filteredVenue}/>
<ReviewSection filteredVenue = {filteredVenue} id = {id}/>
</div>
)
}
export default Venue
Lastly, in mid section I want to pull some information out of the venue data, passed as props as filteredvenue. I'm extracting this data with the following function:
import { useEffect,useState } from 'react'
import { convertToStars } from "../../helperFunctions";
const MidSection = ({ filteredVenue }) => {
const extractRatings = () => {
const foodRatings = []
filteredVenue[0].reviews.map((rating) => {
foodRatings.push(rating.ratingFood)
})
return {foodRatings}
}
const {foodRatings} = extractRatings()
I logged out foodRatings and it returned the data I wanted. However when I refreshed the browser, the app crashed, giving the error:
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'reviews')
I'm assuming this is some sort of asynchronous error and that the browser is rendering this component before the data has been returned. Unsure why this is happening since I'm using async/await in the initial firebase useVenues function, and the filteredVenue object is being mapped through elsewhere in this component with no problems. Suggestions?
import { firebase } from './firebaseConfig'
problem is with firebase config you are using, when it resolve but have error

Is there anyway to pass state to getServerSideProps

I am new to next.js. I want to pass page state to getServerSideProps. Is it possible to do this?
const Discover = (props) => {
const [page, setPage] = useState(1);
const [discoverResults, setDiscoverResults] = useState(props.data.results);
// console.log(discoverResults, page);
return (
<div>
<Card items={discoverResults} render={(discoverResults) => <DiscoverCard results={discoverResults} />} />
</div>
);
};
export default Discover;
export async function getServerSideProps() {
const movieData = await axios.get(`https://api.themoviedb.org/3/discover/movie?api_key=${process.env.NEXT_PUBLIC_MOVIE_DB_KEY}&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=${page}&with_watch_monetization_types=flatrate`);
return {
props: {
data: movieData.data,
},
};
}
the only way is changing your route with params and recive it in server side :
import { useRouter } from "next/router";
const Discover = (props) => {
const { page } = props;
const router = useRouter();
const goToNextPage = () => {
router.replace(`/your-page-pathname?page=${+page + 1}`);
}
return (
<div>
page is : {page}
<button onClick={goToNextPage}>
next page
</button>
</div>
);
};
export default Discover;
export async function getServerSideProps(context) {
const { page } = context.query;
return {
props: {
page: page || 0,
},
};
}
To read more on the topic, recommend reading: Refreshing Server-Side Props
I recommend to use SWR for handling this kind of api calls
an example of this here:
https://swr.vercel.app/examples/ssr
In this example, it can be seen that the api calls happens in the Server side and it is being cached in the Client side.
For handling the query from the urls. This can be done using the same methods as well following the examples from their documentation of SWR https://swr.vercel.app/docs/pagination#pagination
SWR will help alot of stuffs in the api state management. I really recommend to start learning it as soon as possible..

logging the data but not rendering p tag , why?

I am using firebase firestore and i fetched the data , everything is working fine but when i am passing it to some component only one item gets passed but log shows all the elements correctly.
I have just started learning react , any help is appreciated.
import React, { useEffect, useState } from 'react'
import { auth, provider, db } from './firebase';
import DataCard from './DataCard'
function Explore() {
const [equipmentList, setEquipments] = useState([]);
const fetchData = async () => {
const res = db.collection('Available');
const data = await res.get();
data.docs.forEach(item => {
setEquipments([...equipmentList, item.data()]);
})
}
useEffect(() => {
fetchData();
}, [])
equipmentList.forEach(item => {
//console.log(item.description);
})
const dataJSX =
<>
{
equipmentList.map(eq => (
<div key={eq.uid}>
{console.log(eq.equipment)}
<p>{eq.equipment}</p>
</div>
))
}
</>
return (
<>
{dataJSX}
</>
)
}
export default Explore
You have problems with setting fetched data into the state.
You need to call setEquipments once when data is prepared because you always erase it with an initial array plus an item from forEach.
The right code for setting equipment is
const fetchData = async () => {
const res = db.collection('Available');
const data = await res.get();
setEquipments(data.docs.map(item => item.data()))
}

Categories

Resources