저번 1차 팀프로젝트에 이어 두번째 프로젝트를 시작하게 되었다. 1차 프로젝트때 느꼈던 막연한 두려움 보다는 설레는 마음이 더컸고, 새로운 기능과 스택을 마주한다는 기대감이 컸던것 같다.
1차때보다 백엔드와도 소통을 적극적으로 했고, 프로젝트 결과물도 완성도가 높아진 결과물을 보니 조금은 성장한 것 같아 감회가 새롭다.
기업협업을 나가서는 어떤 성장의 기회가 나에게 찾아올지 기대가 된다.
이 프로젝트는 프립을 참조하여 교육목적상으로 제작하였습니다.
개발기간 : 2022년 10월 31일(월) ~ 2022년 11월 10일(목)
개발인원 : 5명
1. 프론트엔드
매일 오후1시에 15분 정도 Daily Standing Meeting 진행하여 Trello를 작성하고 작업내용을 공유했다
카테고리를 4가지로 나눠서 구분했고, 회의록을 따로 작성하여 공통적으로 봐야할 부분들이 기록되어 있어 그때 그때 확인할 수 있도록 trello를 활용하였다.
전체 프로젝트 과정에서 진행 척도를 파악하기가 수월했다.
useEffect(() => {
const code = new URL(window.location.href).searchParams.get('code');
try {
axios
.post(
`https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}&code=${code}`,
{
headers: {
'Content-type': 'application/x-www-form-urlencoded;charset=utf-8',
},
}
)
.then(res => res.data)
.then(data => {
if (data.access_token) {
basicApi
.post(API.signin, { kakaoAccessToken: data.access_token })
.then(res => res.data)
.then(data => {
localStorage.setItem('token', data.accessToken);
navigate('/');
});
} else {
window.alert('로그인에 실패하였습니다.');
navigate('/login');
}
});
} catch (err) {
alert(err);
}
로그인 페이지에서 카카오로그인 하기 버튼을 눌렀을때 링크 이동을REDIRECT_URI
일치여부등 유효성검증이 되면 토큰을 보내준다.access_token
을 백엔드 API로 보내주고 백엔드에서 access_token
을 기반으로카카오 유저정보를 활용하여 우리사이트에서 사용하는 전용 토큰으로 다시 보내줄때 나는 그 토큰을 저장한다.모달 드롭다운기능 구현
메뉴 아이콘을 클릭하면 드롭다운 메뉴가 나타나고 드롭다운 메뉴가 나타난 상태에서 다시 메뉴 아이콘을 클릭하거나 드롭다운외의 영역을 클릭하면 드롭다운 메뉴가 사라져야했는데 click 이벤트로는 아예 드롭다운메뉴가 나타나지 않아 mousedown으로 처리했었다.
const handleDropdown = e => {
if (isOpen === true) {
setIsOpen(false);
} else {
setIsOpen(true);
}
};
useEffect(() => {
const pageClickEvent = e => {
if (
dropdownRef.current !== null &&
!dropdownRef.current.contains(e.target)
) {
setIsOpen(!isOpen);
}
};
if (isOpen) {
window.addEventListener('mousedown', pageClickEvent);
}
return () => {
window.removeEventListener('mousedown', pageClickEvent);
};
}, [isOpen]);
그런데 문제는 mousedown으로 처리하게되면서 드롭다운이 활성화된 상태에서 다시 메뉴 아이콘을 '클릭' 했을때 드롭다운 메뉴가 사라지지 않는다는 것이다. 클릭이 아닌 마우스를 클릭하고 있는 상태 즉, mousedown일때에만 드롭다운메뉴가 사라지고 마우스를 떼는 순간 다시 드롭다운 메뉴가 나타나기 때문에 움직임이 매우 어색했다.
문제해결은 시행착오에 걸린 시간에 비해 비교적 간단했다. 이벤트를 mousedown으로 할것이 아니라 click으로 바꾸고, e.stopPropagation()
으로 이벤트 버블링을 막아주면 된다.
const handleDropdown = e => {
e.stopPropagation();
if (isOpen === true) {
setIsOpen(false);
} else {
setIsOpen(true);
}
};
useEffect(() => {
const pageClickEvent = e => {
if (
dropdownRef.current !== null &&
!dropdownRef.current.contains(e.target)
) {
setIsOpen(!isOpen);
}
};
if (isOpen) {
window.addEventListener('click', pageClickEvent);
}
return () => {
window.removeEventListener('click', pageClickEvent);
};
}, [isOpen]);
이벤트 버블링이란?
이벤트가 연속하여 발생하는 버블 현상을 의미합니다. 클릭 시점에 해당 위치에서 이벤트가 발생하고 발생하고 다시 겹쳐진 요소를 올라가면서 해당 엘리먼트의 이벤트를 다시 발생시키는 현상을 의미한다. 이 경우 의도하지 않은 두 번째 이벤트가 추가로 발생하여 오류가 발생할 수 있기 때문에event.stopPropagation()
을 사용하며 이 경우 이벤트 버블링은 Firing 하지 않아 이벤트가 발생되지 않는다
react-datepicker
라이브러리를 커스텀해서 사용하였고 공통으로 react-modal
을 사용해 모달창으로 구현하였다.useEffect(() => {
if (subCategories) {
basicApi
.get(
`${API.list}/${categories}/${subCategories}?sort=${
sort ? sort : ''
}&firstDate=${firstDateParams ? firstDateParams : ''}&lastDate=${
lastDateParams ? lastDateParams : ''
}`
)
.then(res => res.data)
.then(data => {
if (firstDateParams || sort) {
setLists(data.data);
} else {
setLists(JSON.parse(data.data[0].products));
}
});
} else {
basicApi
.get(
`${API.list}/${categories}?sort=${sort ? sort : ''}&firstDate=${
firstDateParams ? firstDateParams : ''
}&lastDate=${lastDateParams ? lastDateParams : ''}`
)
.then(res => res.data)
.then(data => {
if (firstDateParams || sort) {
setLists(data.data);
} else {
setTitle(JSON.parse(data.data[0].mainCategories)[0].korName);
setSubCategoryLists(JSON.parse(data.data[0].subCategories));
setLists(JSON.parse(data.data[0].products));
}
});
}
}, [categories, subCategories, lastDateParams, firstDateParams, sort]);
페이지 내에 서브카테고리가 있고 page depth를 나눠서 쿼리스트링을 사용할 api를 요청하는 형식이라 식이 조금 길어진 것같다.const DateForm = ({ startDate, endDate, onChange }) => {
return (
<>
<DatePicker
locale={ko}
selected={startDate}
dateFormat="yyyy년MM월dd일(eee)"
onChange={onChange}
startDate={startDate}
endDate={endDate}
disabledKeyboardNavigation
selectsRange
monthsShown={2}
minDate={new Date()}
inline
wrapperClassName="react-datepicker__header react-datepicker__day"
/>
<DatePickerWrapperStyles />
</>
);
};
일단 DatePickerWrapperStyles
라는 컴포넌트를 생성하고const DatePickerWrapperStyles = createGlobalStyle`
.react-datepicker {
border: none;
}`
createGlobalStyle
이라는 함수를 styled-components 에서 Import하여 만들어진 라이브러리 클래스명에 직접 스타일을 덮어서 전역에서 커스텀 해 줄 수 있다.열린 마음으로 새로운 기술 스택 받아들이기
1차 프로젝트에서는 네트워크 서버 요청 메서드로 fetch
, 스타일 언어로는 scss
, github 명령어로 git merge
를 사용했다면 이번 2차 프로젝트에서는 axios
, styled-components
, git rebase
등 새로운 방법으로 많이 시도 하였다. 지금도 계속 계속 새로운 기술과 언어들이 쏟아져 나오고 있을 것이다. 개발자로서 도태되지 않고 살아남으려면 새로운 기술과 언어들을 배척하지 않고 열린마음으로 받아들일 수 있어야 한다고 생각한다. 물론 새로운 것만 고집하자는 것은 어리석은 생각이지만, 내가 모든 방법을 알고 있고 선택하는것과 옛날 방법만 알기 때문에 이전 방식을 사용하는것은 멀리 봤을때는 큰 차이가 나게될 것이다.
적당한 Deep Dive
나는 이전까지 누군가에게 물어보거나 도움을 요청하지 않았었다. 최대한 나 혼자 어떻게든 해결하려고 했고 구글이 나의 멘토였다면, 이번 프로젝트에서는 멘토님이나 동기들에게 먼저 다가가 무엇이 문제인지 함께 고민해보고 해결해나가는 과정을 경험하면서 무조건 문제에 깊게 파고들고 혼자 해결해내는 것이 정답은 아니라는 것이라는 생각이 들었다. (내가 친 코드는 에러가 났을때 내눈에는 어디에 에러가 났는지 절대 안보인다)
첫 프로젝트와 사뭇 다른 2차 프로젝트였다. 사실 소통을 많이 하려고 노력했는데, 팀원들과 회고할때도 그 부분에 있어서 좋은 피드백을 받아서 뿌듯하다.
사실 새로운 기술 스택을 많이 사용하여서 또 새로운 것을 처음부터 배우는 느낌이라 많이 해맸고 모르는것을 구현해야해서 많이 힘들었지만, 같이 고민해주고 생각해주는 팀원들 덕분에 이겨낼 수 있었던 것 같다. 막상 내가 맡은 기능을 다 구현해내니 성취감이 들고 계속 새로운 기능들에 도전하고 싶은 마음이 든다.
다음 프로젝트때도 팀원들과 blocker 공유 하면서 같이 헤쳐나가는 프로젝트를 하고싶고, 새로운 기술들을 많이 접하고 싶다