React - 从 Firebase 获取集合并更新状态以呈现子组件

React - Getting collection from Firebase and updating state to render a child component

请原谅我的无知,但我仍处于学习 React 和 firebase 的早期阶段。

我正在尝试实现一些功能,让用户可以点击一个类别,然后他们将被导航到这个 ViewItemPage 组件,我正在尝试根据用户的类别从 firebase 获取一个集合点击。检索到集合后,我将尝试 select 集合中的随机项并使用该数据呈现另一个子组件。

我假设这要么是一个生命周期问题and/or我完全错误地使用了反应钩子,但我一直在试图解决这个问题太久了

import { collection, query, where, getDocs } from 'firebase/firestore';
import { db } from '../firebase';
import { useLocation } from 'react-router';
import { AnotherComponent } from './AnotherComponent ';

export function ViewItemPage() {
  const { state } = useLocation();
  const { category } = state;
  const [items, setItems] = useState([]);
  const [loading, setLoading] = useState(true);
  const [selectedItem, setSelectedItem] = useState();

  const itemsRef = collection(db, 'items');
  const getItems = async (e) => {
    try {
      const q = query(itemsRef, where('category', '==', category));
      const querySnapshot = await getDocs(q);
      querySnapshot.forEach((doc) => {
        setItems({ data: doc.data() });
      });

      setLoading(false);
    } catch (err) {
      console.log(err.message);
    }
  };

  const getRandomItem = () => {
    const randomItem = items[Math.floor(Math.random() * items.length)];
    setSelectedItem(randomItem);
  };

  useEffect(() => {
    getItems();
    // eslint-disable-next-line
  }, [loading]);

  useEffect(() => {
    getRandomItem();
    // eslint-disable-next-line      
  });
return <AnotherComponent category={category} item={selectedItem} />;
}

在上面的示例中,我尝试使用 forEach 循环来更新状态,但我也尝试映射响应:

setItems(
         querySnapshot.docs.map((doc) => ({ ...doc.data(), id: doc.id }))
       );

它有相同的结果,子组件似乎被传递并且是空对象,并且在尝试读取任何项目属性时抛出错误

经过更多的学习、反复试验和重构之后,它似乎正在按照我的预期运行。这是代码,以防其他人发现它有用

import React, { useState, useEffect, useRef } from 'react';
import { collection, query, where, getDocs } from 'firebase/firestore';
import { db } from '../firebase';
import { useLocation } from 'react-router';
import { AnotherComponent} from './AnotherComponent ';

export function ViewItemPage() {
  const { state } = useLocation();
  const { category } = state;
  const [loading, setLoading] = useState(true);
  const [randomItem, setRandomItem] = useState();
  let itemArray = [];

  const getItems = async () => {
    try {
      const q = query(
        collection(db, 'items'),
        where('category', '==', category)
      );
      const querySnapshot = await getDocs(q);

      querySnapshot.forEach((doc) => {
        itemArray = [...itemArray, doc.data()];
      });

      setRandomItem(
        itemArray[Math.floor(Math.random() * itemArray.length)]
      );
      setLoading(false);
    } catch (err) {
      console.log(err.message);
    }
  };

  useEffect(() => {
    getItems();
    // eslint-disable-next-line
  }, [loading]);

  if (loading) {
    return (
      <div
        style={{
          display: 'flex',
          flexDirection: 'column',
          alignItems: 'center',
          justifyContent: 'center',
          height: '100vh',
        }}
      >
        Loading the data
      </div>
    );
  }
  return <AnotherComponent item={randomItem} />;
}