当我开始我的项目时,我创建了一个处理 API 数据的类。现在我不知道如何管理异步以正确显示数据。我在 fetchOpenings 中有一个 console.log ,它将在控制台上显示我的列表,但不会将其显示在屏幕上。如果我编辑代码,它会显示我的数据。
export class ChessGameFetcher {
async fetchGameArchives(): Promise<void> {
try {
const response = await fetch(this.apiURL);
if (response.ok) {
const data = (await response.json()) as ChessGames;
this.games = data.games;
} else {
throw new Error("Network response was not ok");
}
} catch (error) {
if (error instanceof Error) {
console.error(
"There has been a problem with your fetch operation: ",
error.message
);
} else {
console.error("An unexpected error occurred");
}
}
}
logOpenings(): void {
this.games.forEach((game) => {
let opening = game.eco;
let accuracyWhite = game.accuracies?.white ?? 0;
let accuracyBlack = game.accuracies?.black ?? 0;
let date: Date = new Date(2024, 4);
const extractedDate = this.extractUTCDateTime(game.pgn);
if (extractedDate) {
date = extractedDate;
}
this.processChessString(game.pgn);
const sidePlayed =
game.white.username === this.username ? "white" : "black";
let result =
sidePlayed === "white" ? game.white.result : game.black.result;
result = this.normalizeResult(result);
const match = opening.match(this.regex);
if (match && match[1]) {
opening = match[1].replace(/-$/, "").replace(/-/g, " ");
}
const matchedOpening = this.predefinedOpenings.find((openingName) =>
opening.includes(openingName)
);
if (matchedOpening) {
this.updateOpeningResults(matchedOpening, result, opening);
} else {
console.log(`Unmatched opening: ${opening}`);
}
this.gameInfo.push(
new GameInfo(
result,
opening,
sidePlayed,
game.black.username,
accuracyWhite,
accuracyBlack,
date
)
);
});
}
async init(): Promise<void> {
await this.fetchGameArchives();
this.logOpenings();
this.returnOpeningData();
this.getPercentages();
//console.log(this.user_opening_percentages);
}
}
import React, { useState, useEffect } from "react";
import { ChessGameFetcher } from "./classes/ChessGameFetcher";
import { PercentageInfo } from "./classes/PercentageInfo";
function OpeningForm() {
const [stat, setStat] = useState<PercentageInfo[]>([new PercentageInfo(0, 0, 0, 0), new PercentageInfo(0, 0, 0, 0)]);
const [username, setUsername] = useState("");
const [loading, setLoading] = useState(false);
const [submitted, setSubmitted] = useState(false);
const listStats = stat.map((st, index) => (
<li key={index}>{st.toString()}</li>
));
async function fetchOpenings() {
const gameFetcher = new ChessGameFetcher(username);
const openingStats: PercentageInfo[] = gameFetcher.user_opening_percentages;
console.log(openingStats);
setStat(openingStats);
}
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
setSubmitted(true); // Trigger the useEffect to fetch data
fetchOpenings();
};
return (
<>
<form onSubmit={handleSubmit}>
<label>
Enter your name:
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
</label>
<button type="submit">Submit</button>
</form>
<ul>{listStats}</ul>
</>
);
}
export default OpeningForm;
我尝试添加一个 useEffect ,但它似乎没有做任何事情。我尝试在 setSet() 上调用 wait,但这并没有真正执行任何操作。
您对异步构造函数的使用有点奇怪。我建议将您的
ChessGameFetcher
类重构为以下内容:
export class ChessGameFetcher {
username: string // Not 100% if you need this, but you use it when instantiating your class
constructor(username: string) {
this.username = username
}
async fetchGames() {
await this.fetchGameArchives();
this.logOpenings();
this.returnOpeningData();
this.getPercentages();
}
... // everything else you already have except the init() method
}
更改的想法是将异步功能分离到其自己的方法中,以便您可以在调用
setStat
之前显式等待它运行。现在你可以像这样在 React 组件中初始化你的类:
async function fetchOpenings() {
const gameFetcher = new ChessGameFetcher(username);
// By using await we ensure we don't try to setStat before all the games are fetched
await gameFetcher.fetchGames();
const openingStats: PercentageInfo[] = gameFetcher.user_opening_percentages;
console.log(openingStats);
setStat(openingStats);
}
设置完成后,您可以从
<ul>
变量加载 stat
。删除listStats
,代码中的这个变量仅在组件渲染时初始化一次,并且永远不会工作。
return (
<>
<form onSubmit={handleSubmit}>
<label>
Enter your name:
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
</label>
<button type="submit">Submit</button>
</form>
<ul>{
stat.map((st, index) => (<li key={index}>{st.toString()}</li>))
}</ul>
</>
)