이 솔루션은 Time tracking dashboard challenge on Frontend Mentor 챌린지 참여 결과물입니다.
시간 관리 웹페이지를 만들었다.
react component로 화면을 구성했고,
json 파일을 읽어들여서
클릭한 버튼에 따라 화면이 바뀌도록 했다.
삽질포인트가 두 개 있었다.
가장 어려웠던 것은 TrackedTime 컴포넌트 6개를 for문으로 호출해내는 것이었다.
(그냥 return 문 안에서
...
이런 식으로 복붙하는게 제일 쉽고 어쩌면 더 깔끔했을 것 같지만
연습을 위해서 어떻게든 복붙은 피해보려고 했다.)
시도해본 오답들은 아래와 같다.
(1) return문 안에서 for문 쓰기
function App{
//unrelated codes...
return (
for(let i=0; i<timedata.length(); i++){
<TrackedTime title={timedata[i].title} timeframes={Timeframe} current={timedata[i].current} previous={timedata[i].previous} />
}
)
}
(timedata[i].current, timedata[i].previous도 안된다. 해결방법은 후술한다.)
구글링해본 결과 이건 그냥 문법적으로 안된다. jsx return문 안에는 for문이 있을 수 없다.
(2) return문 안에서 map
function App{
//unrelated codes...
return (
timedata.map((time, idx)=>
<TrackedTime title={timedata[i].title} timeframes={Timeframe} current={timedata[i].current} previous={timedata[i].previous> />
)
)
}
이렇게 했더니 에러는 따로 없었지만 컴포넌트가 화면에서 보이지 않았다.
(혹시 왜인지 아시는 분 댓글 남겨주시면 감사하겠습니다.)
(3) return문 밖에서 map, 변수로 전달해주기
function App{
//unrelated codes...
const timeComponents = timedata.map((time, idx)=>
<TrackedTime title={time.title} timeframes={Timeframe} current={updatecurrentTime(idx, Timeframe)} previous={updatepreviousTime(idx, Timeframe)}/>
);
return (
{timeComponents}
)
}
왜 (2)는 안되고 (3)은 되는지 모르겠다.
이렇게 하면 가독성이 엄청 별로였다.
다른 방법을 찾게 되면 꼭 업데이트하겠다.
json 파일은 아래와 같았다.
{
"title": "Work",
"timeframes": {
"daily": {
"current": 5,
"previous": 7
},
"weekly": {
"current": 32,
"previous": 36
},
"monthly": {
"current": 103,
"previous": 128
}
}
},
{
"title": "Play",
"timeframes": {
"daily": {
"current": 1,
"previous": 2
},
"weekly": {
"current": 10,
"previous": 8
},
"monthly": {
"current": 23,
"previous": 29
}
}
},
//이하 생략
그래서 for문을 돌면서 object.timeframes.[daily/weekly/monthly].[current/previous]를
상황에 맞게 바꾸어 주어야만 했다.
우선, profile 영역에서 Timeframe를 state로 선언하고 클릭에 따라 바뀔 수 있게 해 주었다.
function App(){
let [Timeframe, setTimeframe] = useState("day"); //기본값을 day로 주었다.
return (
<div className="time">
<button className="daily" onClick={()=>setTimeframe("day")}>Daily</button>
<button className="weekly" onClick={()=>setTimeframe("week")}>Weekly</button>
<button className="monthly" onClick={()=>setTimeframe("month")} >Monthly</button>
</div>
)
}
그 다음으로, profile 영역에서 변한 Timeframe를 TrackedTime 컴포넌트의 props로 주었다.
const timeComponents = timedata.map((time, idx)=>
<TrackedTime title={time.title} timeframes={Timeframe} current={} previous={}/>
)
그리고 이 Timeframe에 맞게 current와 previous를 업데이트해주는 함수를 만들었다.
function updatecurrentTime(idx, Timeframe){
if(Timeframe==="day") return timedata[idx].timeframes.daily.current;
else if(Timeframe==="week") return timedata[idx].timeframes.weekly.current;
else if(Timeframe==="month") return timedata[idx].timeframes.monthly.current;
}
function updatepreviousTime(idx, Timeframe){
if(Timeframe==="day") return timedata[idx].timeframes.daily.previous;
else if(Timeframe==="week") return timedata[idx].timeframes.weekly.previous;
else if(Timeframe==="month") return timedata[idx].timeframes.monthly.previous;
}
마지막으로 TrackedTime props로 함수를 호출해 주었다.
const timeComponents = timedata.map((time, idx)=>
<TrackedTime title={time.title} timeframes={Timeframe} current={updatecurrentTime(idx, Timeframe)} previous={updatepreviousTime(idx, Timeframe)}/>
)
jsx 전체 코드는 아래와 같다.
function App() {
let [Timeframe, setTimeframe] = useState("day");
function updatecurrentTime(idx, Timeframe){
if(Timeframe==="day") return timedata[idx].timeframes.daily.current;
else if(Timeframe==="week") return timedata[idx].timeframes.weekly.current;
else if(Timeframe==="month") return timedata[idx].timeframes.monthly.current;
}
function updatepreviousTime(idx, Timeframe){
if(Timeframe==="day") return timedata[idx].timeframes.daily.previous;
else if(Timeframe==="week") return timedata[idx].timeframes.weekly.previous;
else if(Timeframe==="month") return timedata[idx].timeframes.monthly.previous;
}
const timeComponents = timedata.map((time, idx)=>
<TrackedTime title={time.title} timeframes={Timeframe} current={updatecurrentTime(idx, Timeframe)} previous={updatepreviousTime(idx, Timeframe)}/>
);
return (
<>
<div className="wrapper">
<div className="profile">
<div className="user">
<div className="pic"></div>
<div className="repfor">Report for</div>
<div className="name">Jeremy Robson</div>
</div>
<div className="time">
<button className="daily" onClick={()=>setTimeframe("day")}>Daily</button>
<button className="weekly" onClick={()=>setTimeframe("week")}>Weekly</button>
<button className="monthly" onClick={()=>setTimeframe("month")} >Monthly</button>
</div>
</div>
{timeComponents}
</div>
<Attribution />
</>
);
}
function TrackedTime(props){
return(
<div className={"tracktime " + props.title}>
<div className={"top " + props.title}>
<div className="title">{props.title}</div>
<div className="showntime">
<div className="current">
{props.current}hrs
</div>
<div className="previous">
Last {props.timeframes} - {props.previous}hrs
</div>
</div>
</div>
</div>
)
}
처음으로 리액트를 활용해서 무에서 유를 창조해 보았다(?)
컴포넌트를 언제 어떻게 만들어야 하며
props와 state가 어떻게 쓰이는지 연습해 볼 수 있었다.
하지만 여전히 코드가 깔끔하지 않은 것 같아 스스로 매우 불만족스럽다...
강의 몇개 더 듣고 와야겠다.
이런... 공부하면 할수록 할 게 더 많아지는 것 같다.
방학동안에 많이 배워둬야지.