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} />;
}
请原谅我的无知,但我仍处于学习 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} />;
}