我正在撰寫一個食譜應用程式。食譜的食譜存盤在 yaml 檔案中,并且這些檔案以靜態方式存盤。當我加載該站點時,它會自動訪問一個 index.json 檔案,其中所有食譜都被索引并一個接一個地加載它們并將它們添加到一個陣列中。然后將該陣列提供給 setRecipe 方法,在該方法中它應該相應地更新 dom。這不會發生。我已經嘗試過 console.log 一點,這樣做時,我會記錄預期的資料,但是一旦我重繪 頁面,情況就不再如此了。正在完成對 yaml 檔案的請求。為什么會這樣?
完整的源代碼
import React, { useState, useEffect } from 'react';
import jsyaml from 'js-yaml'
import { ListGroup, ListGroupItem } from 'react-bootstrap';
const basePath = '/k0chbuch'
const recipeStore = basePath '/recipe-store'
const index = recipeStore '/index.json'
const RecipeList = () => {
const [recipes, setRecipes] = useState([]);
useEffect(() => {
fetchAllRecipes();
}, []);
const fetchAllRecipes = () => {
fetch(index)
.then(response => {
if (!response.ok) {
throw new Error("HTTP error " response.status);
}
return response.json()
})
.then(recipeIndex => {
let store = []
recipeIndex.forEach(element => {
fetch(recipeStore '/' element '.yaml')
.then(res => res.blob())
.then(blob => blob.text())
.then(text => jsyaml.load(text))
.then(recipeObject => {
store.push(recipeObject)
})
})
return store
})
.then((all) => setRecipes(all));
}
return (
<div>
<h1>Rezepte:</h1>
<ListGroup>
{recipes.map((r)=>(<ListGroupItem>{r.Titel}</ListGroupItem>))}
</ListGroup>
</div>
);
};
export default RecipeList;
簡單的 Yaml 示例:
---
Titel: Hackbraten
Autor: d3v3lop3r
Komplexitaet: 1
Portionen: 4
Zutaten:
- 1000g Hack
- 150g Zwiebeln
- Gewürze nach Wahl
Zubereitung: |
Zuerst wird das Hack gewürzt, dann die Zwiebeln braten und dem Hack zugeben. Kr?ftig kneten, dann bei 200°C eine Stunde backen.
Kommentar: Schmeckt am besten mit Kartoffeln!
uj5u.com熱心網友回復:
您的問題在于第二次填充store陣列.then():使用時Array.prototype.forEach,請記住這return并沒有真正做任何事情。在解決承諾之前,您不會等待決議 blob。事實上,菊花鏈式 promise 的這一部分會立即決議:
.then(recipeIndex => {
let store = [];
recipeIndex.forEach(element => {
fetch(...);
});
// `store` is returned immediately without waiting for forEach!
return store;
})
相反,我建議使用Array.prototype.map來回傳一組基于 off 的承諾recipeIndex。然后 return Promise.all(),這確保所有的承諾都得到解決:
fetch(index)
.then(response => {
if (!response.ok) {
throw new Error("HTTP error " response.status);
}
return response.json();
})
.then(recipeIndex => {
const promises = recipeIndex.map((element) => {
return fetch(recipeStore '/' element '.yaml')
.then(res => res.blob())
.then(blob => blob.text())
.then(text => jsyaml.load(text));
});
return Promise.all(promises);
})
.then((all) => setRecipes(all));
使用for回圈呢?(可以,但不推薦)
另一種方法是使用for回圈,然后您可以使用 async/await。但是,我通常不建議這樣做,原因有兩個:
forloopawait意味著每個請求是在彼此之后而不是并行調度的,這會增加延遲。上面的Array.prototype.map解決方案同時調度 fetch 請求。- 那里的一些 linter 不鼓勵在內部嵌套異步回呼
.then()
但是,如果您想嘗試一下,for回圈是完全可行的:
fetch(index)
.then(response => {
if (!response.ok) {
throw new Error("HTTP error " response.status);
}
return response.json();
})
.then(async (recipeIndex) => {
const recipes = [];
for (const element of recipeIndex) {
const recipe = await fetch(recipeStore '/' element '.yaml')
.then(res => res.blob())
.then(blob => blob.text())
.then(text => jsyaml.load(text));
recipes.push(recipe);
}
})
.then((all) => setRecipes(all));
uj5u.com熱心網友回復:
useEffectuseEffect基于作為鉤子的第二個引數傳遞的依賴陣列運行。
試試這個,
const [recipes, setRecipes] = useState([]);
useEffect(() => {
if(!recipes && recipes.length == 0){
fetchAllRecipes();
}
}, [recipes])
這將導致您的useEffect鉤子在狀態更改后立即呼叫,但僅在狀態為或陣列的長度為 0recipes時才會導致fetchRecipes()函式呼叫recipesnull
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/419648.html
標籤:
