reactjs 使用来自一个useEffect的数据在另一个useEffect中或在TS中的useEffect之外

syqv5f0l  于 2023-02-08  发布在  React
关注(0)|答案(3)|浏览(155)

我有一个React组分如下

import { useCallback, useEffect, useState } from "react";
import "../style.css";
import styles from "./calendarBody.module.css";
import {
  PlayerData,
  MonthlyPlayerData,
  MonthlyPlayerDataNoCost,
} from "../../../ProjectTypes.types";
import { useLocation } from "react-router-dom";

export const CalendarBody = ({
  date,
  month,
  year,
}: {
  date: Date;
  month: number;
  year: number;
}) => {
  const [playerData, setPlayerData] = useState<PlayerData[]>([]);

  const [monthlyPlayerData, setMonthlyPlayerData] =
    useState<MonthlyPlayerData>();

  let location = useLocation();
  let url = location.pathname;
  let player = url.substring(url.lastIndexOf("/") + 1);
  const adjustedMonthNumber = month + 1;

  const getPlayerData = useCallback(
    async (url: string) => {
      const response = await fetch(url, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ player, year, adjustedMonthNumber }),
      });
      const data = await response.json();
      setPlayerData(data);

      let consolidatedPlayerData = await data.reduce(
        (accumulator: MonthlyPlayerData[], current: any) => {
          if (
            !accumulator.some(
              (acc: MonthlyPlayerData) => acc.name === current.name
            )
          ) {
            let obj = {
              name: current.name,
              hours_played: +current.hours_played,
              confirmedAndNotPlayed:
                current.confirmation === "yes" && +current.hours_played === 0
                  ? 1
                  : 0,
              notConfirmedAndPlayed: current.confirmation === "no" ? 1 : 0,
            };
            accumulator.push(obj);
          } else {
            //Find index of specific object using findIndex method.
            let objIndex = accumulator.findIndex(
              (obj: MonthlyPlayerData) => obj.name == current.name
            );

            //update the specific object using index
            accumulator[objIndex].hours_played += +current.hours_played;

            if (current.confirmation === "yes" && +current.hours_played === 0) {
              accumulator[objIndex].confirmedAndNotPlayed++;
            }

            if (current.confirmation === "no") {
              accumulator[objIndex].notConfirmedAndPlayed++;
            }
          }

          return accumulator;
        },
        []
      );

      const monthlyData: MonthlyPlayerData = await consolidatedPlayerData.map(
        (obj: any) => ({
          ...obj,
          cost:
            obj["hours_played"] * 90 +
            (obj["confirmedAndNotPlayed"] + obj["notConfirmedAndPlayed"] > 1
              ? (obj["confirmedAndNotPlayed"] +
                  obj["notConfirmedAndPlayed"] -
                  1) *
                45
              : 0),
        })
      );

      setMonthlyPlayerData(monthlyData);

      return data;
    },
    [player, month, year]
  );

  useEffect(() => {
    getPlayerData("/api/getPlayerDetails");
  }, [getPlayerData]);

  const playedDatesUnFormatted = playerData.map((a: PlayerData) => a.date);
  const playedDates = playedDatesUnFormatted.map((b) => b.substring(0, 10));

  let firstDayOfMonth = new Date(year, month, 1).getDay(), // getting first day of month
    lastDateOfMonth = new Date(year, month + 1, 0).getDate(); // getting last date of month

  const renderEmptyDays = (day: number) => {
    let keyVal = `e${day}`; //'e' is there just to differentiate the keys of "Empty days" with "Days"
    return <li className="inactive" key={keyVal}></li>;
  };

  let emptyDaysOfMonth = [];
  for (var i = 0; i < firstDayOfMonth; i++) {
    emptyDaysOfMonth.push(i);
  }

  const renderDays = (day: number) => {
    //check is the day is today (if yes, we will highlight it on the calendar)
    let isToday =
      day === date.getDate() &&
      month === new Date().getMonth() &&
      year === new Date().getFullYear()
        ? "active"
        : "";

    //check if the days are weekends (for weekends, we shot stop symbol)
    let isWeekend =
      new Date(year, month, day).getDay() === 0 ||
      new Date(year, month, day).getDay() === 6;

    //check is the player has played on this date
    let played = playedDates.includes(
      new Date(year, month, day).toISOString().substring(0, 10)
    );

    let playedHrs = "-";
    let confirmation = "";

    // If the player has played on that day, we get additional data to show it appropriately on the calendar;
    if (played) {
      let playedData: PlayerData[] = playerData.filter((item: PlayerData) => {
        return (
          item["date"].substring(0, 10) ===
          new Date(year, month, day).toISOString().substring(0, 10)
        );
      });
      playedHrs = playedData[0].hours_played;
      confirmation = playedData[0].confirmation;
    }

    if (isWeekend) {
      return (
        <li key={day} className={`${styles.weekend}`}>
          <div className={`${styles.dayInfo} ${styles.weekend}`}>
            <div className={`${styles.day} ${styles.weekend}`}>{day}</div>
            <div
              className={`material-symbols-rounded ${styles[`${isToday}`]} ${
                styles.weekend
              } ${styles.hrs}`}
            >
              Block
            </div>
          </div>
        </li>
      );
    } else {
      return (
        <li key={day}>
          <div className={`${styles.dayInfo}`}>
            <div className={`${styles.day}`}>{day}</div>
            <div
              className={`${styles[`${isToday}`]} ${styles.weekday} ${
                styles.hrs
              } ${
                confirmation === "yes" && +playedHrs > 0
                  ? `${styles.playedAsPlanned}`
                  : ""
              } ${
                confirmation === "no" && +playedHrs > 0
                  ? `${styles.notConfirmedButPlayed}`
                  : ""
              }
              ${
                confirmation === "yes" && +playedHrs == 0
                  ? `${styles.notTurnedUp}`
                  : ""
              }`}
            >
              {playedHrs}
            </div>
          </div>
        </li>
      );
    }
  };

  let daysOfMonth = [];
  for (var i = 1; i <= lastDateOfMonth; i++) {
    daysOfMonth.push(i);
  }


  return (
    <div className={`${styles.calendar}`}>
      <div className={`${styles["summary-text"]}`}>{`${player} has played for ${
        monthlyPlayerData.hours_played
      } hrs with ${
        monthlyPlayerData.confirmedAndNotPlayed +
        monthlyPlayerData.notConfirmedAndPlayed
      } penalty hrs.Total cost is ${monthlyPlayerData.cost}.`}</div>      
    </div>
  );
};

monthlyPlayerData的计算依赖于API调用中的data。但是,我在getPlayerData函数中做了所有事情,包括设置状态。我做错了什么?
无论我做什么,我都会收到TS错误“monthlyPlayerData”可能“未定义”

将鼠标悬停在错误上会显示以下内容。

monthlyPlayerData如下所示。

{ confirmedAndNotPlayed: 2,​​
cost: 585,​​
hours_played: 6,​​
name: "Siva",​​
notConfirmedAndPlayed: 0 }

o7jaxewo

o7jaxewo1#

无论我做什么,我都会收到TS错误"monthlyPlayerData"可能"未定义"
monthlyPlayerData值来自API响应,因此在调用完成之前,它可能是undefined。此外,您在设置状态时没有提供 * default * 值。

useState<MonthlyPlayerData>(); // no default value for "monthlyPlayerData"

您可以使用 * 可选链接 * 来确保monthlyPlayerDataundefined的可能性。

monthlyPlayerData?.hours_played
          // ^^^^^^^^ optional chaining
qjp7pelc

qjp7pelc2#

你没有用任何值初始化它,正因为如此,它最初得到的值是undefined

const [monthlyPlayerData, setMonthlyPlayerData] = useState<MonthlyPlayerData>();

可以使用安全链接运算符(?)安全地访问其属性。请使用monthlyPlayerData?.hours_played而不是monthlyPlayerData.hours_played

xqkwcwgp

xqkwcwgp3#

当你从API请求数据时,monthlyplayerData实际上可能是未定义的。也许你可以尝试为monthlyPlayerData设置一个默认值。

const [monthlyPlayerData, setMonthlyPlayerData] =
useState<MonthlyPlayerData>({ });

相关问题