Ich habe Probleme mit dem Konzept von Promise
in JavaScript. Ich schreibe eine React-App, die einen GET
Aufruf an einen separaten API-Dienst in Java ausführt, und möchte dessen Status in einem useState()
-Hook speichern. Hier ist mein fetch
Code:
const ratingsUrl = "%URL%";
const base64 = require("base-64");
const login = "login";
const password = "password";
function fetchRatings() {
return fetch(ratingsUrl, {
method: "GET",
headers: new Headers({
Authorization: "Basic " + base64.encode(login + ":" + password),
}),
})
.then((response) => response.json())
.catch(handleError);
}
Und jetzt versuche ich, seinen Status in einem Hook in meiner Seitenkomponente zu speichern:
function DisplayPage(){
const [ratings, setRatings] = useState(fetchRatings());
.
.
.
}
Jetzt kehren die Daten zurück, befinden sich jedoch in einem Promise
, was später zu Fehlern führt:
Promise {<pending>}
__proto__: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: Array(20)
Was ich tun muss, ist, die Daten in einem Hook zu initialisieren und in einem Table
zurückzugeben, damit ich sie abbilden kann. Wenn ich jedoch versuche, so etwas zu tun
ratings.map()
Ich erhalte einen TypeError in der Konsole mit der Aufschrift ratings.Map is not a function
.
Ich bin mir bewusst, dass die fetch
- Bibliothek Daten asynchron zurückgibt, aber alles, was ich wirklich möchte, ist, dass die PromiseResult
in einem useState()
- Hook gespeichert wird, damit ich weiter unten Operationen ausführen kann Linie.
4 Antworten
async
Methoden geben Versprechen zurück. Wenn Sie das Ergebnis eines Versprechens direkt in Ihrer Statusvariablen setRatings
festlegen, erhalten Sie ein Versprechen.
Normalerweise wird dies wie folgt umgeschrieben:
function DisplayPage(){
const [ratings, setRatings] = useState(null);
useEffect(() => {
fetchRatings
.then(result => setRatings(result))
.catch(err => console.error(err));
}, []);
if (ratings === null) return <div>loading...</div>;
/* .. do your thing .. */
}
Wie wäre es damit ,
const [ratings, setRatings] = useState();
useEffect(()=>{
fetch(ratingsUrl, {
method: "GET",
headers: new Headers({
Authorization: "Basic " + base64.encode(login + ":" + password),
})}).then((response) => {let res = response.json();
setRatings(res)
})
.catch(handleError);
},[])
Ich würde empfehlen, den useEffect-Hook zu verwenden, um den Anfangszustand festzulegen (ähnlich wie componentDidMount).
Wenn die erwartete Antwort beispielsweise ein Array ist.
const [ratings, setRatings] = useState([]);
Aktualisieren Sie dann im useEffect-Hook den Status, wenn Sie eine Antwort von Ihrer Abrufanforderung erhalten. Auf diese Weise können Sie Fehler vermeiden, wenn Sie beispielsweise Bewertungen in Ihrem DOM irgendwo zuordnen, bevor die Anforderung abgeschlossen ist.
useEffect(){
fetch(ratingsUrl, {
method: "GET",
headers: new Headers({
Authorization: "Basic " + base64.encode(login + ":" + password),
}),
})
.then((response) => {
response.json()
})
.then(res => setRatings(res))
.catch(handleError);
Da der Abruf asynchron ausgeführt wird, können Sie Ihren Status nicht mit dem unmittelbaren Ergebnis des Aufrufs von fetchRatings initialisieren.
Glücklicherweise gibt es ein paar ziemlich einfache Möglichkeiten, damit umzugehen. Sie können Ihren Status mit einem leeren Wert initialisieren und dann aktualisieren, sobald fetchResults behoben ist:
function DisplayPage() {
// initially ratings will be undefined
const [ratings, setRatings] = useState();
// update state when fetchResults comes back
fetchResults().then(response => setRatings(response));
// ...
Im obigen Beispiel wird dies aus Gründen der Lesbarkeit weggelassen. Dies geschieht jedoch im Allgemeinen über useEffect wird also ausgeführt, wenn Ihre Komponente bereitgestellt wird oder wenn sich relevante Eingaben (normalerweise Requisiten, sogenannte Abhängigkeiten für den Effekt) ändern:
function DisplayPage() {
const [ratings, setRatings] = useState();
useEffect(() => {
fetchResults().then(response => setRatings(response));
}, []) // empty dependencies array will cause the effect to run only once, on mount
// ...