我想顯示一個映射串列,其中“用戶名”是 Firebase 實時資料庫中與每個條目的作者相對應的條目值。
以下代碼在get(UsernameRef).then((snapshot) =>{})范圍內按預期回傳未定義的參考錯誤,'UserName' is assigned a value but never used并且'UserName' is not defined
const [RecipeLibrary, setRecipeLibrary] = React.useState([]);
React.useEffect(() => {
const RecipeLibraryRef = ref(db, "Recipes/");
onValue(RecipeLibraryRef, (snapshot) => {
const RecipeLibrary = [];
snapshot.forEach((child) => {
const AuthorUserId = child.key;
child.forEach((grandChild) => {
const UserNameRef = ref(db, "Account/" AuthorUserId "/username");
get(UserNameRef).then((snapshot) => {
const UserName = snapshot.val();
});
RecipeLibrary.push({
name: grandChild.key,
author: UserName,
...grandChild.val(),
});
});
});
setRecipeLibrary(RecipeLibrary);
console.log({ RecipeLibrary });
});
}, []);
我試過了:
- 使用 React 狀態傳遞變數 -> 不能在 React 內部使用 useEffect
- 匯出和匯入回傳所需用戶名的單獨函式->回傳只能在內部范圍內使用
- 在 Firebase 獲取范圍內移動串列 .push -> React.useState 無法再訪問該串列
我希望這里有一個簡單的解決方案,因為我是新手。您的時間和建議將很重要,謝謝!
更新:
I got the RecipeLibrary array to contain the desired "UserName" entry, named author by moving the array .push inside the .then scope. Here is a log of that array at set (line 59) and at re-render (line 104).
child.forEach((grandChild) => {
const UserNameRef = ref(db, "Account/" AuthorUserId "/username");
get(UserNameRef).then((snapshot) => {
const UserName = snapshot.val();
RecipeLibrary.push({
name: grandChild.key,
author: UserName,
authorId: AuthorUserId,
...grandChild.val(),
});
});
});
});
setRecipeLibrary(RecipeLibrary);
console.log(RecipeLibrary);
However, now the mapped list is not rendering at all on screen.
Just some added context with minimal changes to original code, been stuck on this so long that I'm considering a full re-write at this point to jog my memory. Oh and here is the bit that renders the mapped list in case:
<Box width="75%" maxHeight="82vh" overflow="auto">
{RecipeLibrary.map((RecipeLibrary) => (
<Paper
key={RecipeLibrary.name}
elevation={3}
sx={{
etc...
uj5u.com熱心網友回復:
這是一個棘手的問題 - 最簡單的選擇可能是移動push() 并 setRecipeLibrary()在then()回呼內部,因此它們都在同一范圍內,但這會產生一些可怕的副作用(例如,為檢索到的每個配方觸發重新渲染)。
目標(您已盡最大努力實作)應該是等待所有配方首先加載,然后用于setRecipeLibrary()將完整串列設定為狀態。假設get()回傳一個 Promise,一種方法是使用await異步函式:
const [RecipeLibrary, setRecipeLibrary] = React.useState([]);
React.useEffect(() => {
const RecipeLibraryRef = ref(db, "Recipes/");
onValue(RecipeLibraryRef, (snapshot) => {
// An async function can't directly be passed to useEffect(), and
// probably can't be accepted by onValue() without modification,
// so we have to define/call it internally.
const loadRecipes = async () => {
const RecipeLibrary = [];
// We can't use an async function directly in forEach, so
// we instead map() the results into a series of Promises
// and await them all.
await Promise.all(snapshot.docs.map(async (child) => {
const AuthorUserId = child.key;
// Moved out of the grandChild loop, because it never changes for a child
const UserNameRef = ref(db, "Account/" AuthorUserId "/username");
// Here's another key part, we await the Promise instead of using .then()
const userNameSnapshot = await get(UserNameRef);
const UserName = userNameSnapshot.val();
child.forEach((grandChild) => {
RecipeLibrary.push({
name: grandChild.key,
author: UserName,
...grandChild.val(),
});
});
}));
setRecipeLibrary(RecipeLibrary);
console.log({ RecipeLibrary });
};
loadRecipes();
});
}, []);
請記住,這Promise.all()不是絕對必要的。如果它的使用使您的可讀性降低,您可以改為在普通 for 回圈(不是 forEach)中執行 grandChild 處理,允許您在await不映射結果的情況下使用,因為它不會在回呼函式中。
如果snapshot.docs不可用但您仍然可以使用snapshot.forEach(),那么您可以將 Firebase 物件轉換為類似于Convert A Firebase Database Snapshot/Collection To An Array In Javascript 的陣列:
// [...]
// Change this line to convert snapshot
// await Promise.all(snapshot.docs.map(async (child) => {
await Promise.all(snapshotToSnapshotArray(snapshot).map(async (child) => {
// [...]
// Define this somewhere visible
function snapshotToSnapshotArray(snapshot) {
var returnArr = [];
snapshot.forEach(function(childSnapshot) {
returnArr.push(childSnapshot);
});
return returnArr;
}
請注意,如果get()以某種方式沒有回傳 Promise ......我擔心解決方案會變得不那么簡單。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/425736.html
