HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
📎
운영진을 위한 문서 모음
/
🤧
주차별 액션 안내
/
👯
19~20주차
/
💌
19-20주차 액션 포인트
/손수림/
📝
노션 클로닝의 사본
📝

노션 클로닝의 사본

배포 링크


손수림의 notion
https://notion-clone-theta.vercel.app/
 

프로젝트 개요


  • 기간 : 2021.08.29 ~ 2021.09.05
  • 목표 : vanilla JS를 컴포넌트 방식으로 노션 클론 구현하기
  • 내용 : 노션처럼 글 작성, 수정, 삭제를 할 수 있는 온라인 에디터 사이트입니다.
  • 프로젝트 진행 시 문제점
    • 유지보수 문제 - 노션이 생각보다 복잡한 UI로 이루어져 있었고, html에 태그를 작성하여 개발하는 환경이 아닌 오로지 JS로만 태그들을 생성하고 스타일링 해야하는 상황이기 때문에 복잡한 UI일 수록, 컴포넌트 코드의 길이가 길어지고 추후 유지보수의 문제가 생길 것 같다는 생각이 들었습니다.
    • 컴포넌트 세분화 문제 - 컴포넌트를 너무 세분화를 시켜서 컴포넌트 갯수와 관계없이 이벤트를 계속 위로 올리는 형태의 구조가 되어 버렸습니다. 이러한 구조를 비효율적이라 생각을 했고 프로젝트에 잘못 접근했다는 생각이 들어 현재 React에서는 어떻게 관리하고 있는지 찾아보게 되었습니다.
  • 프로젝트 문제점 해결 방법
    • CSS도 고려하여 견고하게 설계 - 부트스트랩의 CSS명과 태그들의 구조들을 참고하여 컴포넌트들의 구조에 대한 큰 틀을 기획했습니다.
    • 컴포넌트의 역할 구체화 - 각 컴포넌트의 역할과 구조를 분명히 정의함과 동시에 클래스 명까지 반영된 프로젝트의 초안을 작성했습니다.
    • Vuex와 Event Bus 개념을 차용 - 여러군데에서 이벤트가 발생되기 때문에 store를 이용해서 한 군데에서 이벤트와 로직을 관리하면 좋겠다 생각하여 해당 개념을 차용하였습니다.
  • 느낀 점 및 배운 점 : 컴포넌트 방식의 바닐라JS로는 처음 프로젝트를 진행해보았는데 Vuex나 Eventbus 와 같은 개념들을 차용하여 직접 구현했다는 것이 너무 신기했고 많이 성장했다는 것이 느껴지는 프로젝트였습니다!
 

프로젝트 사용 기술


✔Language

  • HTML
  • CSS
  • JavaScript

⚙Infra

  • Git
  • Fontello

프로젝트 설명


notion image

데이터 흐름

  1. emit 하위 컴포넌트에서 이벤트가 발생합니다. ( Child → Store)
  1. on Store에서 이벤트를 감지합니다. ( Store ← Child)
  1. dispatch gettersStore를 이용하여 해당하는 로직을 실행한 뒤, 결과가 반영된 데이터를 가져옵니다. (Store)
  1. commit 변경된 데이터와 렌더링이 필요한 내용을 담아 App 컴포넌트에 전달합니다. ( Store → App)
      • APP 컴포넌트의 데이터는 commit으로만 변경이 가능합니다.
  1. 비동기 통신 이후 처리될 렌더링관련 로직은 settesrElement에서 실행됩니다.
  1. Store에서 전달받은 내용으로 APP 컴포넌트에서 state와 needRender(렌더링이 필요한 컴포넌트) 하위 컴포넌트로 전달합니다. (App → Child)
  1. state는 모두 업데이트되지만 needRender에 의해 필요한 부분만 다시 렌더링이 됩니다. (App → Child)
 

디렉토리 구조와 역할

  • main.js : root에 App을 생성
  • App.js: 최상위 컴포넌트
    • route 처리
    • Store에서 데이터(nextState, needRender)를 받은 뒤, 하위 컴포넌트들에게 전달
  • api : api관련 js 파일
    • config : api기본 설정 파일
    • notion : notion api 파일
  • assets : style에 필요한 요소
    • css : css관련 파일 (index, reset, fontello)
    • font : 사용된 font (openSans, fontello)
    • images : 페이지 내 이미지 (index, 404)
  • components : 페이지 내 하위 컴포넌트
    • modal
      • Modal.js : Modal 하위 요소 생성, 동기적인 UI 로직 실행 → Store에 이벤트 emit
      • ModalBody.js : Modal의 Title,Content를 렌더링
      • ModalHeader.js : Modal 상단의 페이지로 열기, x 버튼 렌더링
    • posts
      • PostsPage.js : Posts 하위 요소 생성, 동기적인 UI 로직 실행 → Store에 이벤트 emit
      • PostsPageBody.js : document 렌더링
      • PostsPageNoData.js : index 렌더링
    • sidebar
      • Sidebar.js : Sidebar 하위 요소 생성, 동기적인 UI 로직 실행 → Store에 이벤트 emit
      • SidebarHeader.js : notion 타이틀 렌더링
      • SidebarBody.js: document 트리(navlist) 렌더링
      • SidebarFooter.js : 새 페이지 버튼 렌더링
  • pages : 페이지 컴포넌트
    • MainPage.js: 하위 컴포넌트 (Sidebar, posts, modal)들을 가지고 있는 컴포넌트
    • NotFoundPage.js: 404 Error 페이지 컴포넌트
  • store : App 컴포넌트 상태 저장소
    • index.js
      • APP컴포넌트의 상태 변경 (commit)
      • 하위 컴포넌트의 이벤트 감지 후 비동기 작업 진행 (dispatch)
    • gettersLi.js : openedLi의 데이터를 가공하여 반환
    • gettersState.js : state의 데이터를 가공하여 반환
    • settersElement.js : 가공된 state를 이용하여 비동기적인 UI 로직 실행
  • utils : 유틸 함수
    • emitter.js: on과 emit으로 이벤트를 관리
      • on : 이벤트를 바인딩 (감지)
      • emit: 이벤트를 실행
    • render.js : 렌더링에 필요한 함수 (Ex. 태그의 스타일, 컨텐츠 변경 등)
    • selector.js: 전역으로 사용되는 element 선택관련 함수
    • templates.js: 컨텐츠 없는 template 태그를 생성
    • storage.js: 스토리지 get, set 함수
    • valid.js: getters의 valid를 체크

회고록

10일간의 바닐라 JS로 Notion 클론 코딩 프로젝트 회고 ( + Vuex, EventBus 따라해보기 )
해당 페이지의 내용으로 08월 29일 TIL의 내용 중 일부를 가져왔다. 이 때는 이 전에 진행했던 투두리스트 정도의 스펙만 생각을 하고 CSS를 신경 쓰지 않고 기능 구현에만 초점을 두고 구현을 시작하였다! 실제로 구현을 많이 했다고 했지만.. API 요청 부분 과 트리 구조를 그리는 기능 만 구현되어 있었다..ㅎㅎ 기능 구현 도중, 추후 CSS를 입힐 생각을 하니 아래와 같은 문제점이 생겼다.
10일간의 바닐라 JS로 Notion 클론 코딩 프로젝트 회고 ( + Vuex, EventBus 따라해보기 )
https://velog.io/@surim014/Notion-%ED%81%B4%EB%A1%A0-%EC%BD%94%EB%94%A9-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0-Vuex-EventBus-%EB%94%B0%EB%9D%BC%ED%95%B4%EB%B3%B4%EA%B8%B0
10일간의 바닐라 JS로 Notion 클론 코딩 프로젝트 회고 ( + Vuex, EventBus 따라해보기 )
 

구현 화면