const CollectionPage = () => {
const currentPath = usePathname().substring((usePathname().lastIndexOf("/")
) 1)
const colPath = currentPath
// console.log(colPath)
const [details, setDetails] = useState()
const [list, setList] = useState([])
// const docRef = doc(db, 'users', 'user1');
// const colNameRef = collection(db, 'users', 'user1', 'colName');
const animeListRef = collection(db, 'users', 'user1', 'animeList');
const q = query(animeListRef, where("colName", "==", colPath));
useEffect(() => {
const getId = async () => {
onSnapshot(q, (querySnapshot) => {
let animes = [];
querySnapshot.forEach((doc) => {
animebyId(({ ...doc.data(), id: doc.id }.animeId)).then((response) => animes.push(response.media[0]));
});
setList(animes);
// console.log(list)
})
}
getId()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
console.log(list)
// console.log(list.length)
return (
<>
{list === undefined ?
<>still Loading.....</> :
<>
<p>list</p>
{/* <ImageList sx={{ width: '100%', height: '100%' }}>
<ImageListItem key="Subheader" cols={2}>
<ListSubheader component="div">{colPath}</ListSubheader>
</ImageListItem>
{list.map(item => {
return (
<>
<ImageListItem key={item.id}>
<img
src={`${item.coverImage.extraLarge}?w=248&fit=crop&auto=format`}
srcSet={`${item.coverImage.extraLarge}?w=248&fit=crop&auto=format&dpr=2 2x`}
alt={item.title.english ? item.title.english : item.title.romaji}
loading="lazy"
/>
<ImageListItemBar
title={item.title.english ? item.title.english : item.title.romaji}
subtitle={item.author}
actionIcon={
<IconButton
sx={{ color: 'rgba(255, 255, 255, 0.54)' }}
aria-label={`info about ${item.title.english ? item.title.english : item.title.romaji}`}
>
<InfoIcon />
</IconButton>
}
/>
</ImageListItem>
</>
)
})}
</ImageList> */}
</>
}
</>
)
}
export default CollectionPage
as we can see on this console there are arrays, but whenever use map in jsx I never render this array.
Let's straight:
- I think my mistake is listening to a query to from a firestorm, then usestate on the result is make this code fail to map. look on useEffect
- animeById is an API file, using Axios, in another page is good and can render the map function. but in this page, I want to try using query snapshot.
UPDATE
This is my animeById function
async function animebyId(id, page = 1, perPage = 1) {
const query = `
query ($id: Int, $page: Int, $perPage: Int) {
Page(page: $page, perPage: $perPage) {
media(id: $id, type: ANIME) {
id
title {
romaji
english
}
siteUrl
coverImage {
extraLarge
}
bannerImage
description(asHtml: false)
status
season
seasonYear
startDate {
year
month
day
}
duration
source
type
genres
averageScore
meanScore
}
}
}`;
let variables = {
page: page,
perPage: perPage,
id: id
};
const headers = {
"Content-Type": "application/json",
Accept: "application/json",
};
return await axios.post(`https://graphql.anilist.co`, {
query,
variables,
headers
}).then(response => {
// console.log('api response entry', response.data.data.Page)
return response.data.data.Page
}).catch((err) => console.log(err.message))
}
CodePudding user response:
I would recommend using for-of loop instead of forEach it will wait until your loop is complete before calling setList, below is the code you can try
useEffect(() => {
const getId = async () => {
onSnapshot(q, async (querySnapshot) => {
let animes = [];
for (let doc of querySnapshot) {
const response = await animebyId(({ ...doc.data(), id: doc.id }.animeId));
animes.push(response.media[0]);
}
setList(animes);
})
}
getId()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
EDIT: can you give it try to below useEffect
useEffect(() => {
const getId = async () => {
onSnapshot(q, async (querySnapshot) => {
let animes = [];
querySnapshot.forEach(doc => {
const anime = { ...doc.data(), id: doc.id };
animes.push(anime);
})
const animesNew = [];
for (let anime of animes) {
const response = await animebyId(anime.animeId);
animesNew.push(response.media[0]);
}
setList(animesNew);
})
}
getId()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
CodePudding user response:
This is how you should do it:
const getId = async () => {
// Snapshoot returns Unsubscribe to prevent from memoryleaks you need to ivoke it later like unsub()
const unsub = onSnapshot(q, async (querySnapshot) => {
if (querySnapshot.empty) return // If there is no data just do nothing.
let promises = []
for (let doc of querySnapshot.docs) {
// Do all promisess in parallel
promises.push(animebyId(({ ...doc.data(), id: doc.id }.animeId)))
}
// Await all promises
const results = await Promise.all(promises)
if(!results.length) return // If no result abort.
let animes = []
for (let doc of results) {
animes.push(doc.media[0]);
}
setList(animes);
})
}