当 API 处理在另一个类中时,使用异步在 React 中显示表单

问题描述 投票:0回答:1

当我开始我的项目时,我创建了一个处理 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,但这并没有真正执行任何操作。

reactjs typescript async-await react-tsx
1个回答
0
投票

您对异步构造函数的使用有点奇怪。我建议将您的

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>
  </>
)
© www.soinside.com 2019 - 2024. All rights reserved.