我有一个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 }
3条答案
按热度按时间o7jaxewo1#
无论我做什么,我都会收到TS错误"monthlyPlayerData"可能"未定义"
monthlyPlayerData
值来自API响应,因此在调用完成之前,它可能是undefined
。此外,您在设置状态时没有提供 * default * 值。您可以使用 * 可选链接 * 来确保
monthlyPlayerData
是undefined
的可能性。qjp7pelc2#
你没有用任何值初始化它,正因为如此,它最初得到的值是
undefined
。可以使用安全链接运算符(
?
)安全地访问其属性。请使用monthlyPlayerData?.hours_played
而不是monthlyPlayerData.hours_played
xqkwcwgp3#
当你从API请求数据时,monthlyplayerData实际上可能是未定义的。也许你可以尝试为monthlyPlayerData设置一个默认值。