StudyLog 처음 시작 → typeScript 공부해보기!
typescipt를 공부하고, 실제 프로젝트에 적용해보고 싶어서 처음 시작한 프로젝트다.
🔍 왜 ? StudyLog ?
우선 만들고 싶은 어플리케이션의 조건은 다음과 같았다.
- 내가 기술적으로 성장할 수 있는 기능이 들어간 어플리케이션
- 내가 많이 사용할 것 같은 사이트
- 예쁜 UI 중요도 5 (예쁜게 최고!)
- 지루해지지 않게 빠르게 만들 수 있는 간단한 사이트
✏️ TodoList 기능
원래 todoList는 모바일로 Todomate를 사용하기도 하고 최근에는 노션으로만 사용했다. 노션으로 관리 했었는데 화요일 이후면 다시 접속하지 않다.
왜 들어가지 않을까?
- 동기부여가 되지 않는다. 나는 무언가 할때 당근이 있어야지 잘 하는 타입인데 할일을 완료하면 뱃지를 주지도 않고, 굳이 열심히 할 필요성을 느끼지 못했다.
- UI가 예쁘지만, 조금 더 직관적이고 더 예뻤으면 했다.
🕰️ StopWatch 기능
stopwatch로 얼만큼 공부 했는지 기록 하곤 했는데 이 기능들을 모두 추가한 어플리케이션을 직접 만들면 어떨까 하는 생각이 들었다. 계획을 다음과 같이 짰다. 내가 좋아하는 노트북에 붙이고 다니는 고양이 스티커가 있다. 그 스티커만 보면 기분이 좋다. 이 스티커를 이용해서 내 동기부여를 자극하면 좋겠다는 생각을 했다.
우선 기획을 완성하자 마자 디자인을 구상했다. 디자인은 Figma로 했고, 다음과 같이 디자인했다.
디자인
아쉬운 점
내가 필요한 서비스를 만들고 사용하니, 매일 들어가게 된다. 내가 필요한 것을 만드니, 더 재미있게 만들었던 것 같다. 이제 아쉬운 점을 정리해보자
📝 커스텀 훅
커스텀 훅을 공부하고 사용한 것은 처음이었는데 우선 커스텀 훅을 공부하면서,, 오류가 났었는데 왜 났었는지 헤매다가 내가 쓴 글이있다.
그리고 커스텀 훅을 만들면서, 비슷한 코드가 너무 많았다. firestore는 값을 수정하는 기능을 제공해주지 않아. document를 가져오고, 데이터를 없애고, 새로운 데이터를 만들어 덮어 씌워야한다.
try {
const docRef = doc(db, 'users', user.uid, 'studyLogWeek', weekId);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
const studyLogWeeks = docSnap.data()?.studyLogWeek;
const selectedDay = studyLogWeeks?.find(
(week: StudyLogDayType) => week.day === day
);
const dayIndex = WEEK_DAY.findIndex((weekDay) => weekDay === day);
const updatedStudyLogWeek = [
...studyLogWeeks.slice(0, dayIndex),
{
...selectedDay,
studyTime: totalSecond,
},
...studyLogWeeks.slice(dayIndex + 1),
];
await updateDoc(docRef, {
studyLogWeek: updatedStudyLogWeek,
});
toast.success('공부 시간 저장 완료', {
position: 'top-right',
autoClose: 2000,
hideProgressBar: true,
closeOnClick: true,
theme: 'light',
});
}
} catch (error) {
setErrorMessage('공부 시간 저장 중 오류 발생');
toast.error(errorMessage, {
position: 'top-right',
autoClose: 2000,
hideProgressBar: true,
closeOnClick: true,
theme: 'light',
});
} finally {
setIsLoading(false);
}
};
이 코드는 스탑워치의 시간을 저장하는 커스텀 훅에서 가져온 코드이다. 사용자가 공부 시간 저장하기 버튼을 눌렀을 때, 요일 데이터에서 studyTime 속성이 현재 공부한 시간으로 업데이트 된다.
try {
const docRef = doc(db, 'users', user.uid, 'studyLogWeek', weekId);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
const studyLogWeeks = docSnap.data()?.studyLogWeek;
const selectedDay = studyLogWeeks?.find(
(week: StudyLogDayType) => week.day === day
);
const dayIndex = WEEK_DAY.findIndex((weekDay) => weekDay === day);
const updatedStudyLogWeek = [
...studyLogWeeks.slice(0, dayIndex),
{
...selectedDay,
isCatStickerApplied,
},
...studyLogWeeks.slice(dayIndex + 1),
];
await updateDoc(docRef, {
studyLogWeek: updatedStudyLogWeek,
});
}
} catch (error) {
setError(error);
} finally {
setIsLoading(false);
}
};
그리고 이 코드는 useSaveCatSticker.tsx 커스텀 훅으로, 모든 Todo를 완료 했을 때, isCatStiker 속성을 true로 바꿔주는 요청이다.
weekId로 document를 가져오고, 요일을 선택하고, 주 데이터 전체를 업데이트 해야했다.(firestore 너무 복잡해..)
-> 두 개의 코드가 너무 비슷해보이지 않나요? ..
이런 커스텀 훅의 공통된 로직을 하나의 함수로 처리해서 합칠 수 있을 것 같다.
📝 스탑워치 기능
- 스탑워치가 브라우저가 실행될 때만 돌아간다. 브라우저가 잠겨있거나 꺼져있을 때는 스탑워치도 같이 멈춰 시간을 측정하기 힘들다. 이 기능도 개선해보고 싶다.
- 사용자가 저장 버튼을 클릭할 때만 시간이 저장된다. 이 기능에 대해서는 고민을 많이 했다.스탑워치 기능을 구현 하면서 고민했던 것들을 정리해보고자 한다. 일단 스탑워치에 필요한 함수들을 만들었다.
- 시간을 계속 서버로 업데이트 해야할까?
- 서버에 주기적으로 시간을 업데이트하는 방법을 고려했지만, 계속 업데이트할 수는 없으니 (성능측면에서)
- 사용자가 저장하고 싶을 때 최종 시간을 저장하면, 요청을 한 번만 보내도 되어서 좋을 것 같다.
- 날짜별 스탑워치 활성화 : 서버에서 오늘 날짜를 어떻게 처리할까? (없어진 기능)
- 오늘이 아닌 날짜의 스탑워치의 버튼은 비활성화 된다. → time이라는 속성을 서버로부터 받아온다.
- 서버에 오늘의 데이터를 따로 받아올 것. OR
- boolean값으로 오늘을 나타낼 것.
- 시간을 계속 서버로 업데이트 해야할까?
📝 최적화
사용자는 항상 예측한 대로 어플리케이션을 사용하지 않는다. 투두리스트의 경우, 하루에 해야할 일이 100개 이상인 사람은 어떻게 할까. 투두 리스트가 100개, 1000개를 넘어서 10000개까지 추가하는 상황이 온다면? 이 경우는 고려를 하지 못했다. 마침 다음 초록 스터디 미션이 바로 이 가상화와 최적화에 대한 미션이다. useMemo, useCallback을 공부 한 후에 바로 최적화를 적용해보고 싶다.