10일간의 바닐라 JS로 Notion 클론 코딩 프로젝트 회고 ( + Vuex, EventBus 따라해보기 )

surim014·2021년 9월 16일
45

Project

목록 보기
1/2
post-thumbnail

프로젝트 접근 순서 🤔

해당 페이지의 내용으로 08월 29일 TIL의 내용 중 일부를 가져왔다.

이 때는 이 전에 진행했던 투두리스트 정도의 스펙만 생각을 하고 CSS를 신경 쓰지 않고 기능 구현에만 초점을 두고 구현을 시작하였다!

실제로 구현을 많이 했다고 했지만.. API 요청 부분트리 구조를 그리는 기능만 구현되어 있었다..ㅎㅎ

기능 구현 도중, 추후 CSS를 입힐 생각을 하니 아래와 같은 문제점이 생겼다.

문제점 🤢

노션은 생각보다 복잡한 UI로 이루어져 있었고, html에 태그를 작성하여 개발하는 환경이 아닌 오로지 JS로만 태그들을 생성하고 스타일링 해야하는 상황이기 때문에 복잡한 UI일 수록, 컴포넌트 코드의 길이가 길어지고 추후 유지보수의 문제가 생길 것 같다는 생각을 했다.

하루동안 열심히 삽질을 하고 30일인 바로 다음날 프로젝트의 구조 자체를 전부 다시 정의하고 새롭게 만들기로 마음먹었다!

해결 방안 💡

1. CSS도 고려하여 견고하게 설계하기

오로지 UI를 위해 리팩토리를 결정한 터라, 명확한 UI의 구조를 짜는 것을 목표로 했다. 하지만 마크업에 대한 이해도가 아직 부족하고 잘 못하는 상황에서 짜야했기 때문에 처음 시작은 막막했다.

"이런 경우 어떤걸 참고해야할까?" 고민을 하였고 그 결과, 부트스트랩이라는 UI 라이브러리를 떠올렸다!

물론 부트스트랩을 가져다 사용하면 좋겠지만, 되도록이면 라이브러리 사용없이 진행을 해보고 싶어서 CSS 명과 태그들의 구조들을 참고하여 컴포넌트들의 구조를 생각하기 시작했다.

2. 컴포넌트의 역할 구체화하기

전체적인 틀을 먼저 생각을 하고, 각 컴포넌트의 역할과 구조를 분명히 정의함과 동시에 클래스 명까지 반영된 프로젝트의 초안을 작성했다!

AS-IS


< 이벤트 흐름을 표현한 이미지 >


< state 흐름을 표현한 이미지 >

그런데 위와 같이 너무 세분화를 시켜서 그런지.. 컴포넌트 갯수와 관계없이 이벤트를 계속 위로 올리는 형태의 구조가 되어 버렸다.. 나는 이러한 구조를 비효율적이라 생각을 했고 프로젝트에 잘못 접근했다는 생각이 들어 현재 React에서는 어떻게 관리하고 있는지 찾아보게 되었다.

찾아보니 Redux라는 개념이 있었고 이걸 이해하고 코드로 구현을 하고 싶었지만..^^ 아쉽게도 리액트는 해본 적이 없어 짧은 시간내에 해당 형태로 구현하기는 힘들었다.. 대신 잠시 배웠던 VuexEventBus를 차용하면 어떨까? 라는 생각을 했다!

TO-BE

"상태 관리"라는 키워드에서 Store를 떠올렸고, "이벤트 전달"이라는 키워드에서 EventBus를 떠올렸다.

Store 만들어보기 🏠

Vuex와 EventBus를 떠올린 이유

  • 현재 컴포넌트들은 상태가 존재하며 공유하고 있다.
  • 데이터는 단방향으로만 흘러야 하기 때문에 이벤트를 올려주어야 한다.
  • 이벤트를 올려주지 않는다면 dispatchEventaddEventListener를 이용하여 App컴포넌트로 바로 이벤트를 주는 방법이 있었지만, 이렇게 되면 이벤트의 흐름과 로직 파악이 어려워질 것 같다고 생각을 했다.

Store의 역할 💪

위의 과정을 거쳐 생각해낸 스토어의 역할은 하위 컴포넌트와 APP 컴포넌트를 연결시켜주는 일종의 미들웨어 같은 역할을 하고 있다. 하위 컴포넌트에서 해당하는 액션을 호출하면 store는 데이터를 가공하여 app에게 전달해주는 형태로 구현하였다.

Emitter의 역할 💪

다양한 이벤트를 보내야 하기 때문에 이벤트를 받는 쪽은 on, 이벤트를 보내는 쪽은 emit이라는 객체를 만들어 이벤트를 받는 쪽인지 보내는 쪽인지 더 명확하게 표현하고 단위를 구분지었다.

Store를 활용한 이벤트 로직 🔄

store를 활용하여 변경된 이벤트 로직은 아래와 같다.

  1. 하위 컴포넌트에서 이벤트가 emit (발생)
  2. store는 이벤트를 on (감지)
  3. 이벤트에 해당하는 action을 호출
  4. store에서 action을 통해 상태를 가공
  5. App으로 변경된 상태를 commit

Store의 데이터 흐름 🔄

  1. 하위 컴포넌트에서 이벤트가 발생하여 store로 이벤트를 실행

  2. 해당하는 액션을 dispatch라는 함수를 통해 호출

2_1. API Request optiongetter 함수에 전달하여 호출

2_2. Storeoption이 반영된 Next State 값을 받음

  1. Setter 함수에 Next State 통신 이후 동기적으로 결과를 반영 + App 의 상태를 업데이트 시킬 수 있는 mutation 에 결과를 commit

  1. mutation은 다시 emit을 이용하여 App 컴포넌트로 바뀐 상태 값을 전달

전체적인 순서는 아래와 같다.

App은 전달받은 state를 현재 state값으로 변경하고 하위 컴포넌트들에게 전달하게 된다.

데이터 로직의 구분 ✂️

위와 같이 데이터를 다루는 부분의 레이어를 나눠두어 예외처리, 방어코드, 디버깅을 보다 쉽게 하였다!

UI 로직의 구분 ✂️

동기 처리 UI 로직 (낙관적 업데이트)

API 통신을 기다린 뒤, UI에 반영하면 살짝 딜레이가 발생하기 때문에 낙관적 업데이트 를 진행하였다.

낙관적 업데이트? 서버요청이 성공한다는 가정하에 변경 사항을 반영한 화면의 렌더링을 먼저 하고 서버요청을 보내는 방식

비동기 처리 UI 로직 (Setter)

문서가 생성되고 생성된 문서의 번호를 받은 뒤, 번호를 부여하는 부분과 같이 비동기로 처리되어야 하는 로직은 setter 함수에 정의하였다.

컴포넌트 구조와 역할 💪

App 컴포넌트

  • Store 생성
  • 메인 페이지, 404 페이지 생성
  • 라우터 처리

NotFoundPage 컴포넌트

  • 404 페이지 렌더링
  • Home으로 가기

MainPage컴포넌트

  • 하위 컴포넌트들 생성
  • 하위 컴포넌트들에게 상태 전달
  • APP에서 전달받은 데이터에 의해 선택적 렌더링

하위 컴포넌트 (SideBar, PostsPage, Modal)

  • 하위 컴포넌트 생성
  • UI 동기 처리
  • storeemit으로 이벤트 전달

최하위 컴포넌트 (SideBar, PostsPage, Modal)

  • 실제 element요소에 addEventListener로 부모의 이벤트 바인딩

Store

  • state 변경을 위한 모든 이벤트들을 관리
  • 이벤트를 받고 해당하는 변경된 최신 상태값을 가져옴
  • 비동기로 실행이 되어야 하는 UI 로직 실행
  • 렌더링이 필요한 하위 컴포넌트를 결정
  • App에 변경된 최신 상태값을 전달

감동의 회고 🥺

Keep (좋았던 점으로 유지해 나갈 방향)

  • 각 컴포넌트들의 역할이 분명하여 트러블 슈팅 용이
  • 데이터 로직의 레이어를 나누어 방어코드 구현이 비교적 수월

Problem (겪은 문제점)

  • 낙관적 업데이트 관련 문제
    • 하단 푸터 클릭 시, 새 페이지 무한 생성

Try (겪은 문제점으로 시도해볼 방향)

  • UI 로직에서의 방어코드 강화
  • API, LocalStorage 사용 등 실제 데이터 처리하는 부분의 방어코드 강화

소감 😍

결국 목표했던 방향으로 구현하고 멘토님께 칭찬의 말씀도 들었다...!! 🥰🥰

컴포넌트 방식의 바닐라JS로는 처음 프로젝트를 진행해보았는데 VuexEventbus 와 같은 개념들을 차용하여 내 손으로 직접 구현했다는 것이 너무 신기했고 많이 성장했다는 것이 느껴지는 프로젝트였다! 멘토님께 받은 피드백을 반영하여 앞으로도 꾸준히 디벨롭할 예정이다!!

profile
Junior FrontEnd Developer 😎

8개의 댓글

comment-user-thumbnail
2021년 9월 19일

우와 열심히하신게 느껴지네요~
공부하신 부분을 잘 설명하실 수 있다는 것도 멋집니다!
수고하셨습니다 ~~~😊👍

1개의 답글
comment-user-thumbnail
2021년 9월 23일

notion clone coding이라니, 진짜 대단하네요. :)

1개의 답글
comment-user-thumbnail
2021년 9월 23일

우와 되게 잘 구조분리하여 만드셨네요. ㅎㅎ 직접 효율성을 생각하다가 이벤트버스 개념을 직접 구현해내면서 단순한 ui 개발을 넘어서 시스템 아키텍쳐부분도 배우신듯 해요. 고생하셨습니다. 살짝 번외이긴 한데, 아이패드 필기에 말풍선처럼 붙이는건 어떻게 하시나요? 되게 효율적인 노트테이킹 방법인듯 하여 여쭈어봅니다

1개의 답글
comment-user-thumbnail
2022년 4월 23일

안녕하세요!! 회고 보고 우와,,라는 말밖에.. 안나왔네요~~ 이 글 보고 자극(감동도) 받았습니다..🔥🔥
저도 구조 분리, 데이터 흐름에 초점을 맞춰서 리팩토링 제대로 다시 해봐야겠습니다!
멋있으세요🤗

1개의 답글