https://github.com/bunniesDev/fe-survey-app
https://bunniesdev.github.io/fe-survey-app/
🎉 개요
프로젝트: 프론트엔드 취준생 설문조사 (fe-survey-app)
기획 및 제작: bunniesDev 스터디원들
제작 기간: 2023/01/04 ~ 2023/02/04, 주 1회 2시간씩
주요 기능: 설문 조사, 조사 결과 시각화
타겟층: 함께 부트캠프를 수강 중인 프론트엔드 취준생
🎉 만든 이유
부트 캠프를 수강하면서, 다른 수강생들은 기술 중에서 어떤 기술에 관심이 있고, 어떻게 공부를 하는 지 등, 궁금한 요소들을 정리하고 싶었기때문에 프로젝트를 진행하게 되었습니다.
프로젝트 목표
- 모각코만 진행하던 스터디원들과, 실제 프로젝트를 경험하기 전에 함께 토이프로젝트를 경험하면서 협업 과정을 경험해 보는 것을 목표로 삼았다.
- 토이 프로젝트이기때문에 개인 일정을 방해하지 않는 선에서 진행한다.
🎉 기획과 디자인
기획
- 설문 조사 기능
- 설문 조사 결과 시각화
디자인
부트 캠프 과정에서 피그마를 배웠기 때문에 각자 프론트엔드 취준생 설문조사라는 주제로 디자인을 구현하고, 투표를 통해 하나를 고르기로 결정했다.
아래는 내가 만든 피그마 디자인 링크이다. 선택되지는 않았지만 만들면서 재미있었다.
https://www.figma.com/file/BmzoiZg3UqMeJXRBXxgxbp/Toy-Project?node-id=0%3A1&t=ZTLUatSyE7siQxQh-1
🎉 내가 맡은 역할
- 전체적인 기획
- 설문 조사 결과 시각화
- 파이어 베이스 API
🎉 주요 기능
선택된 chart 타입에 맞는 chart를 보여주기
Chart.js를 사용해서 화면에 그리는 차트의 종류는 Bar, StackedBar, Doughnut 차트였다.
리액트에서 조건부로 렌더링을 해줘야하는 상황이였다. 함께 차트 페이지를 작업하신 팀원과 어떻게 조건부로 차트를 그릴 것인지 많은 이야기를 나누었다.
stackedBar 차트의 경우, 선택지가 2개인 경우에만 사용하기 때문에 props로 해당 차트가 stackedBar를 사용해야하는지 아닌지를 구분하고, bar와 doughnut 차트는 toggle 버튼의 상태에 따라 다르게 렌더링 해주었다.
if (isStacked) {
chart = <StackedBarChart data={data} labels={labels} {...options} />;
} else if (toggle) {
chart = <BarChart {...options} data={data} labels={labels} id={id} />;
} else {
chart = <DoughnutChart data={data} labels={labels} id={id} {...options} />;
}
return (
<Wrapper>
<Card>
<Headr>
<Title>{title}</Title>
{!isStacked ? (
<ToggleButton size="sm" onClick={toggleHandler}>
{toggle ? 'chart' : 'bar'}
</ToggleButton>
) : (
''
)}
</Headr>
<CanvasWrapper minHeight={minHeight} minWidth={minWidth}>
{chart}
</CanvasWrapper>
</Card>
</Wrapper>
파이어베이스에서 데이터를 가져오기
파이어베이스의 파이어스토어를 사용해 설문 조사 데이터를 관리했다.
설문 조사 질문 데이터는 파이어베이스가 아니라 프론트엔드에서 관리했기 때문에 파이어베이스에서 가져올 데이터가 ID 순으로 정렬이 되어있어야 질문과 해당 질문의 설문 조사 결과가 매칭될 수 있었다.
파이어베이스 공식 문서를 참조해서 questions 컬렉션에 존재하는 모든 문서를 가져왔다.
// 파이어베이스
export const getQuestions = async () => {
const collectionRef = collection(db, 'questions');
const queryString = query(collectionRef, orderBy('id')); // ID값으로 정렬
const querySnapshot = await getDocs(queryString);
const temp = [];
querySnapshot.forEach(item => {
temp.push(item.data());
});
return temp;
};
// 설문 조사 데이터
const data = [
{
id: 0,
question: '가장 선호하는 프론트엔드 SPA 라이브러리 / 프레임워크',
answer: ['리액트', '뷰', '앵귤러', '스벨트', '기타'],
},
{
id: 1,
question: '배워보고싶은 새로운 기술 스택은?',
answer: ['리액트 네이티브', '플러터', '타입스크립트', 'Tailwind', '기타'],
},
파이어베이스 데이터 업데이트하기
개선할 사항이 있다. 남은 과정에서 자세히 확인 작성했다.
파이어베이스 구조를 설정할 때, 질문(컬렉션)의 옵션을 5개로 고정시키고 해당 옵션값은 배열로 관리했다.
파이어스토어는 기본적으로 숫자 값을 증가하는 함수 increment를 제공해준다.
문제는 increment가 컬렉션의 문서의 해당 필드 숫자값을 증가 시킨다는 것이다.
- 나는 필드 값을 배열 Array 타입으로 가지고 있고, increment를 사용하려면 해당 문서의 필드 값이 Number여야한다.
그래서 고민한 방법은 2가지가 있다.
- 파이어베이스 문서의 필드를 쪼개서 만든다. ex) option1: 0, option2: 0, …..
- increment를 사용하지 않고, 배열 필드를 통째로 업데이트한다.
Chart를 그리기 위해서 옵션값이 배열인 것이 편하기때문에 나는 2번째 방법을 선택하기로 했다.
......그리고 또 다른 문제가 발생했다.
update를 하는 동안 기존의 배열값을 알 수 없다는 것이다.
검색과 파이어베이스 Doc를 찾아보았지만, 특정 필드가 배열인 경우, 해당 배열의 인덱스 요소의 값만 변경시키는 방법을 찾지 못했습니다. 만약 찾게 되면 댓글로 남겨주시면 감사하겠습니다.
따라서 아래 메서드를 보면, update를 할때, getQuestions 메서드를 사용해서 파이어베이스에 존재하는 데이터를 불러온 후에, 불러온 배열에서 사용자가 선택한 옵션의 idx 값을 +1 해준다.
그 후에 batch를 사용해 수정된 배열을 일괄처리한다.
export const postQuestions = async data => {
try {
// 이전 옵션을 전부 가져오기
const prev = await getQuestions();
const updateData = prev.map((item, idx) => {
const [options] = [item.options];
options[data[idx]]++; // 배열에서 사용자가 선택한 옵션만 +1 해주기
return options;
});
const batch = writeBatch(db);
for (let idx = 1; idx <= updateData.length; idx++) {
batch.update(doc(db, `questions`, `question${idx}`), {
options: updateData[idx - 1],
});
}
await batch.commit();
return {};
} catch (error) {
return {
error,
};
}
};
🎉 소프트 스킬
전체적인 기획과 프로젝트 관리
토이 프로젝트의 첫 시작은 우리 토이프로젝트 해볼까요! 라는 나의 의견이였다. 때문에, 1주차에는 어떤 토이프로젝트를 진행할 지 각자 주제를 생각하는 것이 과제였다.
아무래도 토이 프로젝트를 하자고 주장한 것도 나였고, 내가 생각한 주제가 선택되었기 때문에 자연스럽게 전체적인 기획과 프로젝트 흐름을 담당하게 되었다.
노션에 토이프로젝트 폴더를 만들어서 전체적으로 필요한 기술과 협업 과정, 주차별 목표, 기록 등을 작성했다.
토이 프로젝트를 위해 만든 노션 페이지
노션 페이지를 관리하면서 프로젝트를 진행하기 위해서 필요한 과정, 필요한 기술 등을 정리하면서 내가 어떤 부분이 부족한지 알게 되었다.
나의 부족한 점 & 배운 점
- 나는 Git을 잘 사용하지 못했구나.
- 내가 Git에서 merge, push, commit만 사용했었다는 사실을 더 크게 느낄 수 있는 기회였다.
- 협업과정을 정리하고, 실제로 본 프로젝트를 진행하기 전에 미리 경험해 당황스러운 여러 원격 저장소 주소 fetch와 풀 리퀘스트를 경험해봐서 좋았다.
- 노션에 협업을 위한 Git 사용법을 정리하고, 실제로 Git을 사용하면서 풀리퀘스트, fork를 사용해서 저장소를 관리하는 방법 등을 처음 경험해보았다.
- 나의 멘탈 관리
- 부트 캠프에서 멘탈 치유, 상담등을 제공한다는 공지를 들었기 때문에 신청해볼 생각이다. 그리고, 최대한 사적인 요인이 공적인 일에 영향을 끼치지 않도록 노력해야겠다.
- 하필 토이 프로젝트를 진행하던 1월~2월에 나의 멘탈이 아주 좋지 않던 시기였다. 그리고 현재 진행중인 상태이다. 외적인 요소때문에 프로젝트에 크게 집중하지 못했다는 사실이 너무 부끄러웠다.
- 커뮤니케이션
- 커뮤니케이션은 항상 그때 이러지 말았어야했는데, 라는 후회와 그때 이렇게 말한것은 잘한것 같다 라는 배움이 있는 것 같다.
- 생각보다 조장, 팀장 역할을 많이 하는 것 같다. 대학교 때, 합창 대회 팀장, 사회 공헌 프로젝트 팀장, 합숙 프로젝트 조장 등등…
- 어떻게 말하면 좋을까, 얼마나 말해야 좋을까, 어떤 식으로 말해야 상대방의 기분이 나쁘지않을까, 어떻게 진행하면 프로젝트 진행을 원활하게 진행할 수 있을까, 현재 내 멘탈이 많이 좋지않은 데 말 실수를 하지않을까, 내가 스터디장이 아닌데 너무 말을 많이 하는 것이 아닐까 등등 많은 생각을 했었다.
🎉 트러블 슈팅
Error: Canvas is already in use. Chart with ID '0' must be destroyed before the canvas can be reused.
Canvas is already in use. Chart with ID '0' must be destroyed before the canvas can be reused.
다시 렌더링을 할 때, 차트를 그리는 Canvas가 이미 사용되기 때문에 나타나는 에러이다.
useEffect의 클린업 함수를 사용해서, chart를 지워줘야한다.
useEffect(() => {
const ctx = canvasRef.current.getContext('2d');
Chart.register(...registerables);
Chart.register(ChartDataLabels);
const chart = new Chart(ctx, config);
// 리렌더링 시, 기존 차트 제거
return () => {
chart.destroy();
};
}, []);
🎉 남은 과제
파이어 베이스 업데이트 로직 수정
변경하고 싶은 사항을 이슈로 남겨두었다. 현재 부캠일정때문에 진행하고 있지않지만, 시간이 난다면 개선하고 싶은 부분이다.
https://github.com/bunniesDev/fe-survey-app/issues/43
설문 조사 화면에서도 파이어베이스에서 데이터를 가져와야한다.
그리고 설문 조사 결과를 제출할 때도, postQuestions 내부에서 파이어베이스 데이터를 가져와서 사용한다.
개선 사항으로 생각한 방법은 첫 메인 페이지 입장 시, 파이어베이스에서 데이터를 가져오는 것이다. 그리고 가져온 데이터를 App.js에서 상태로 관리하고(혹은 Context API) 해당 데이터를 설문 조사 결과 페이지와 제출 시에 사용하는 방향으로 개선해보고 싶다.
그렇다면 postQuestions 함수의 기능은 파이어베이스 데이터를 업데이트하는 기능 하나만 같게 되고, 불필요한 통신을 줄일 수 있는 효과가 있을 것이라고 생각한다.
'리뷰 > 회고' 카테고리의 다른 글
[pre-project] 1주차 회고 (1) | 2023.02.17 |
---|---|
프로그래머스 코딩테스트 입문 문제 완성.. (0) | 2023.02.03 |
댓글