数组长度为0,但具有数组对象。我无法在组件中绘制

发布于 2025-02-13 10:22:45 字数 5688 浏览 0 评论 0原文

   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

如我们所见,在此控制台上有数组这个数组。

让我们直截了当:

  1. 我认为我的错误是从火灾中收听查询,然后结果是使该代码无法映射。查看使用效果
  2. AnimeByID是一个API文件,使用Axios在另一页中很好,可以呈现地图功能。但是在此页面中,我想尝试使用查询快照。

update

这是我的动漫症功能

    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))
}
   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:

  1. 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
  2. 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))
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

终止放荡 2025-02-20 10:22:45

我建议使用循环而不是foreach,它将等到您的循环完成之前,然后调用setList,以下是您可以尝试

    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
  }, []);

编辑的代码:
你能给它尝试以下使用效果吗

      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
  }, []);

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
  }, []);
唐婉 2025-02-20 10:22:45

这就是您应该做的:

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);
        })
    }

您需要知道onsnapshot()是可观察的功能。它将触发他在每次更改他听的数据时都具有的功能。如果您更改路线,则需要停止聆听,或者最终有许多开放的观察者。为此,只需调用它返回的功能即可。像unsub()

,请记住,在INIT函数之后,您拥有空的QUERYSNAPSHOT,因为请求将转到服务器,并且需要备份数据。除非您使用浏览器存储“持久性”,否则您可能会从缓存获得第一个“旧数据”。如果您想了解更多信息,请阅读有关Firestore持久性的信息。

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);
        })
    }

You need to know that onSnapshot() is an observable function. It will trigger a function he has inside every time data he listens is changed. If you change route, you need to stop listening, or you end up having many opened observers. To do that, just invoke the function it returns. Like unsub()

And remember that after init that function you have empty querySnapshot because of request is going to server, and it needs to back with data. Unless you're using browser storage "persistence", you may get first "old" data from cache. If you want to know more, read about firestore persistence.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文