JS/운동일지 다이어리 프로젝트

[210925] css, firebase 없이 react 컴포넌트와 map을 이용해 운동 목록 출력하기

kth990303 2021. 9. 25. 15:43
반응형

우선 firebase 연동하기 전에, react 감을 익히기 위해서 아래 이슈를 처리하기로 했다.

view components를 작성해주세요.

달력 컴포넌트
-운동추가 컴포넌트에서 날짜와 진행한 운동을 추가해주면, 그 날짜에 운동을 진행했는지 구별해주는 달력 컴포넌트  를 작성.그 날짜에 어떤 운동을 했는지는, 그 날짜를 클릭하여 운동추가 컴포넌트로 넘어갈 수 있도록 하면 될듯.
-CSS, firebase DB 연동은 지금 하지 않아도 괜찮음.

운동추가 컴포넌트
-운동 리스트 컴포넌트에 기록될 운동을 추가해주는 컴포넌트를 작성할 것.
-CSS, firebase DB 연동은 지금 하지 않아도 괜찮음.

간단한 기능을 갖춘 틀을 작성해준다고 생각하면 될 것 같습니다.
이후 세부기능 및 디테일은 다음에 추가하면 됩니다.
역할 분배, 컴포넌트명, 질문 및 추가사항은 comment 달아주세요.

https://github.com/kth990303/WorkOutDiary/issues/7

 

달력 컴포넌트, 운동추가 컴포넌트 작성하기 · Issue #7 · kth990303/WorkOutDiary

view components를 작성해주세요. 달력 컴포넌트 운동추가 컴포넌트에서 날짜와 진행한 운동을 추가해주면, 그 날짜에 운동을 진행했는지 구별해주는 달력 컴포넌트를 작성. 그 날짜에 어떤 운동을

github.com

나는 이번에 데이터가 주어지면, 그 데이터들을 출력해주는 역할을 맡았다.

데이터는 우선은 아래 형식과 같다.

아이디, 날짜, 그날 한 운동목록을 배열로 받는 데이터로 하였다.

다만, 이 부분은 이후 설계에 따라 날짜에 따른 id 부여가 아닌, 운동에 따른 id 부여로 바뀔 수도 있다.

 

toLocaleDateString() 형식으로 format하는 것이 가장 깔끔하게 나타내주는 것 같아 이용하였다.

toLocaleDateString()을 이용하면 2021-09-24 날짜가 아래와 같이 깔끔하게 표기된다.

Date.toLocaleDateString()

단순히 toString()으로 하면 아래와 같이 출력돼 가독성이 떨어진다.

Date.toString()


App.js

import './App.css';
import React from 'react';
import WorkListCalender from './components/workListCalender';

function App() {
  return (
    <WorkListCalender />
  );
}

export default App;

먼저 App.js를 위와 같이 변경하였다.

로그인에 성공할 경우 가장 먼저 띄워줄 것이 유저의 이번달 운동기록이기 때문이다.

WorkListCalender 컴포넌트가 내가 작업하는 운동달력 컴포넌트이다.

 

WorkListCalendar 컴포넌트

function WorkListCalender(props){    
    const works=[
        // 데이터
    ];
    return(
        <div className="WorkListCalendar">
        <BrowserRouter>
            <div>
            <h1>운동일지 다이어리</h1>
            </div>
            <div className="AddWork">
                <Link to="/add" className="add">추가</Link>
                <Switch>
                    <Route path="/add" component={AddTodayExercise} />
                </Switch>
            </div>
        </BrowserRouter>
        <hr></hr>
            <div className="Calendar">
                {
                    works.map(work=>(
                        <Work work={work}></Work>
                    ))
                }
            </div>
        </div>
    )
}

export default WorkListCalender;

이제 위 코드를 하나하나 뜯어보겠다.


먼저, "/add" api 주소로 이동하면 AddTodayExercise 컴포넌트 링크로 이동할 수 있도록 react-router-dom을 이용해 아래 코드를 작성하였다.

    	<BrowserRouter>
            <div>
            <h1>운동일지 다이어리</h1>
            </div>
            <div className="AddWork">
                <Link to="/add" className="add">추가</Link>
                <Switch>
                    <Route path="/add" component={AddTodayExercise} />
                </Switch>
            </div>
        </BrowserRouter>

add로 갈 수 있는 링크를 생성해주었고,

그 링크를 클릭하여 add로 이동할 경우 Route로 AddTodayExercise 컴포넌트를 띄우게 해주었다.


    	<div className="Calendar">
                {
                    works.map(work=>(
                        <Work work={work}></Work>
                    ))
                }
            </div>

 

그 다음으로, 데이터들을 출력해주기 위해서 위와 같이 map을 이용하여 Work컴포넌트로 works 데이터들을 반환하여 출력해주도록 하였다.

참고로, 위의 <BrowserRouter>과 지금의 <div> 코드를 묶어주는 <div className="WorkListCalendar"> 태그 안에 작성해준 것이다.


Work 컴포넌트

사실 이 컴포넌트에서 삽질을 되게 많이 했다.

특정 날짜에 한 운동 목록을 나타내는 배열인 workName을 어떻게 출력해야할지 고민을 되게 많이 했다.

return 렌더링 내에서 map을 쓰는 방법을 몰랐기 때문에, 처음에는 아래와 같이 코드를 썼었다.

function Work({work}){
    return(
        <div>
            <h3>{work.date} 운동일지</h3>

            <li>{work.workName[0]}</li>
            <li>{work.workName[1]}</li>
            <li>{work.workName[2]}</li>
        </div>
    )
}

그러나, 이렇게 하면 동적배열을 출력해주기 위해선 일일이 배열의 크기만큼 html 코드를 작성해야 한다는 큰 단점이 존재한다.

처음엔 객체 안에 배열을 출력하는 것이다보니, map 안에 map을 써서 출력하게 하는 방법도 사용해봤고 별 방법을 다해봤다

function TodayWorks({todayWorkNames}){
    todayWorkNames.map(todayWorks => <li>{todayWorks}</li>)
}

function Work({work}){
    return(
        <div>
            <h3>{work.date} 운동일지</h3>
            <TodayWorks todayWorkNames={work.workName}></TodayWorks>
        </div>
    )
}
TodayWorks(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.

위 코드도 에러가 떴다. 

 

참고로 foreach도 써봤는데, foreach는 map과 다르게 반환을 해주지 않는 void형이어서 쓰기가 참 애매했다.

우리는 map으로 운동 데이터들을 반환해서 렌더링할 수 있도록 해야 했기 때문이다.

 

위 코드를 Work 컴포넌트 수정 없이 아래의 과정을 거쳐 수정하였다.

  1. 우선 Work 컴포넌트에서 {}를 이용한 value값 출력이 아닌, TodayWorks 컴포넌트를 호출하는 경우이기 때문에, TodayWorks 컴포넌트에서 return을 이용한 렌더링이 필요할 것이다.
  2. map은 여러 개의 값을 리턴하므로 <div>태그로 묶어주자.
function TodayWorks({todayWorkNames}){
    return(
        <div>
            {todayWorkNames.map(todayWorks => <li>{todayWorks}</li>)}   
        </div>
    )
}

function Work({work}){
    return(
        <div>
            <h3>{work.date} 운동일지</h3>
            <TodayWorks todayWorkNames={work.workName}></TodayWorks>
        </div>
    )
}

위와 같이 수정하였더니 결과가 아래와 같이 잘 떴다!

아래와 같은 코드도 가능했다.

function TodayWorks({todayWorkNames}){
    return <li>{todayWorkNames}</li>;
}

function Work({work}){
    return(
        <div>
            <h3>{work.date} 운동일지</h3>
            {work.workName.map(workName=><TodayWorks todayWorkNames={workName}></TodayWorks>)}
        </div>
    )
}

Work 컴포넌트에서 {}로 동적 value값들을 TodayWorks 컴포넌트 return값으로 출력해주도록 한 것이다.

위 코드를 더욱 더 간단히 할 수 있다.

function Work({work}){
    return(
        <div>
            <h3>{work.date} 운동일지</h3>
            {work.workName.map(workName=><li>{workName}</li>)}
        </div>
    )
}

 

{}를 이용한 동적 value 값 출력과, {}를 이용하여 map을 return 렌더링 안에서 사용할 수 있다는 점을 새롭게 배웠다.

근데 배우는 과정이 너무 고통스러웠다...

 

진짜 이 말이 맞는 것 같다


아주 간단한 기능이라 생각했던 것도 이렇게 힘들어했으니 조금 현타가 오긴 한다.

진짜 넘 자유로운 언어다보니 꽤 고통스럽긴 하지만,

오늘의 경험 덕분에 조금이나마 성장했다고 생각하니 만족스럽다.

 

https://github.com/kth990303/WorkOutDiary/pull/12

 

Kth990303 by kth990303 · Pull Request #12 · kth990303/WorkOutDiary

github issue #7 달력 컴포넌트 작성완료 단, 현재 css작업과 firebase DB read를 하진 않았음. 따라서 임시 데이터를 만들어서 출력해주도록 함. Date객체를 toLocaleDateString() 형식으로 format. 단, Date.now() 처

github.com

덕분에 PR을 날릴 수 있었다.

이제 친구가 작성한 addTodayExercise.js PR도 살펴보고 이해해보는 시간을 가지러 가보겠다.

반응형