【问题标题】:Using the data from one useEffect in another useEffect or outside of useEffect in TS在 TS 中将一个 useEffect 中的数据用于另一个 useEffect 或 useEffect 之外
【发布时间】:2023-02-07 18:16:57
【问题描述】:

我有一个反应组件如下

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' is possibly 'undefined'”

将鼠标悬停在错误上会显示这一点。

【问题讨论】:

    标签: reactjs typescript react-hooks


    【解决方案1】:

    无论我做什么,我都会收到 TS 错误“'monthlyPlayerData' is possibly 'undefined'”

    monthlyPlayerData 值来自 API 响应,因此在调用完成之前,它可能是 undefined。另外,您还没有提供默认设置状态时的值。

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

    你可以使用可选链确保monthlyPlayerDataundefined 的可能性。

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

    【讨论】:

      【解决方案2】:

      您没有使用任何值对其进行初始化。因此,它最初获得undefined 的值。

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

      您可以使用安全链接运算符 (?) 来安全访问其属性。代替monthlyPlayerData.hours_played,使用monthlyPlayerData?.hours_played

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

        • 如果我这样做,我会收到错误 Argument of type '{}' is not assignable to parameter of type 'MonthlyPlayerData | (() =&gt; MonthlyPlayerData)'
        猜你喜欢
        • 1970-01-01
        • 2021-12-22
        • 2019-12-05
        • 1970-01-01
        • 2021-11-04
        • 2020-07-11
        • 2021-07-24
        • 2020-08-17
        • 1970-01-01
        相关资源
        最近更新 更多