実現したいこと
TypeError: Cannot read property 'toDate' of nullを解決したい。
前提
Githubの草カレンダーをポートフォリオに実装したいです。
筋トレSNSアプリを作っていまして、firestoreからユーザーの筋トレ記録(簡単に言うと「何をどれだけやったか」です)を取得して配列の形でstateに詰め、react-calenderというライブラリに渡すことで実現したいと考えてます。
発生している問題・エラーメッセージ
二枚目の写真の通り、データを取得して色塗りまではできたのですが、
データを登録するとき(二枚目の写真の左下の「Post」ボタンを押したとき)に一枚目のエラーが発生します。
エラー画面で更新すると、一枚目のように色塗りされていることが確認できます(エラー画面から正常な画面に移る)。
間違っているのがDateオブジェクトの扱い方なのか、useEffectの書き方なのか分からなくなってしまいました。
該当のソースコード
UserTsx
1import React, { useState, useEffect } from 'react' 2import { auth, db } from "../../firebase"; 3import { useSelector } from "react-redux"; 4import { selectUser } from "../../features/userSlice"; 5import { selectProfileUser } from "../../features/profileUserSlice"; 6import ExitToAppIcon from '@material-ui/icons/ExitToApp'; 7import { 8 Avatar, 9 createStyles, 10 makeStyles, 11 Theme, 12} from "@material-ui/core"; 13import CalendarHeatmap from "react-calendar-heatmap"; 14import "react-calendar-heatmap/dist/styles.css"; 15import ReactTooltip from "react-tooltip"; 16import "./User.tsx.scss"; 17 18const useStyles = makeStyles((theme: Theme) => 19 createStyles({ 20 large: { 21 width: theme.spacing(9), 22 height: theme.spacing(9), 23 }, 24 }), 25); 26interface Commit { 27 date: string; 28 count: number; 29} 30const User:React.FC = () => { 31 const classes = useStyles(); 32 const user = useSelector(selectUser); 33 const profileUser = useSelector(selectProfileUser); 34 const [ commits, setCommits ] = useState<Commit[]>([]); 35 const [ commitUser, setCommitUser ] = useState(""); 36 37 useEffect(() => { 38 // if (profileUser) { 39 // setCommitUser(profileUser.name); 40 // } else { 41 // setCommitUser(user.displayName) 42 // } 43 const fetchDate = async() => { 44 try{ 45 await db.collection("training_posts") 46 .where("username", "==", "たらお@redux難しい") 47 .onSnapshot((querySnapshot) => setCommits( 48 querySnapshot.docs.map((doc) => ({ 49 date: doc.data().timestamp.toDate(), 50 count: doc.data().training_array.length, 51 })) 52 )); 53 } catch(err) { 54 console.error(err); 55 } 56 } 57 fetchDate(); 58 }, []) 59 return ( 60 <div className="flex flex-col"> 61 <div className="flex items-center"> 62 <Avatar 63 data-testid="avatar" 64 className={classes.large} 65 src={profileUser.avatar 66 ? profileUser.avatar 67 : user.photoUrl 68 } 69 /> 70 <h3 data-testid="profileUsername" className="font-bold text-xl text-white ml-5"> 71 {profileUser.name 72 ? profileUser.name 73 : user.displayName 74 } 75 </h3> 76 <button 77 data-testid="signOut" 78 className="cursor-pointer bg-transparent border-none outline-none text-white" 79 onClick={async () => { 80 await auth.signOut(); 81 }} 82 > 83 <ExitToAppIcon/> 84 </button> 85 </div> 86 <div className="mt-5 text-whiteSmoke"> 87 <CalendarHeatmap 88 startDate={new Date(new Date().setDate(new Date().getDate() - 120))} 89 endDate={new Date()} 90 values={commits} 91 classForValue={(value) => { 92 if (!value) { 93 return "color-empty"; 94 } 95 return `color-scale-${value.count}`; 96 }} 97 tooltipDataAttrs={(value:any) => { 98 if (!value || !value.date) { 99 return null; 100 } 101 return { 102 "data-tip": `${value.date} has count: ${ 103 value.count 104 }`, 105 }; 106 }} 107 /> 108 <ReactTooltip/> 109 </div> 110 {/* <div> 111 {commits.map((cm) => ( 112 <> 113 <p>{cm.date}</p> 114 <p>{cm.count}</p> 115 </> 116 ))} 117 </div> */} 118 </div> 119 ) 120} 121 122export default User
備考
react-calendar-heatmapのrepo
回答1件
あなたの回答
tips
プレビュー