23.06.27 ~ 23.07.06 동안 진행한 노션 클로닝 프로젝트를 회고해보고자 한다 !
해당 프로젝트는 VanillaJS를 사용하여 노션 페이지를 클로닝하는 프로젝트로, 기본 요구사항은 다음과 같다.
글 단위를 Document로, 각 Document는 여러 개의 Document를 포함할 수 있다.
페이지 좌측에서 글의 목록을 트리형태로 보여주고, 우측에서 글의 제목과 내용을 보여준다.
글의 제목과 내용을 수정하면, 서버에 자동으로 저장되게 한다.
history API를 이용해 SPA 형태로 만든다.
=> 좌측에서 특정 글을 선택하면 우측에서 그 글의 content를 불러온다.
이전에 VanillaJS를 사용하여 간단한 To do List 페이지를 만들어본 경험을 바탕으로, 프로젝트 시작 전 꼭 먼저 생각해야 할 것들을 정리해보았다.
✅ 컴포넌트별 데이터와 기능 확실히 분리 => 컴포넌트 간 의존성 최소화
✅ 컴포넌트 간 공유되는 데이터 및 데이터 관리 메서드
이 2가지 사항을 구현 시작 전에 미리 충분히 고민하고 확실히 정해놓아야, 내가 내 코드를 이해하기 쉬워지고 특정 기능을 추가하려고 할 때에도 어떤 컴포넌트 부분을 건드려야 하는지도 명확해질 것이라 생각했다.
평소 내가 사용해왔던 노션 페이지를 바탕으로 컴포넌트를 어떻게 나눠야 할지 고민해보았다.
이를 바탕으로 각 화면에서 사용되는 데이터들을 생각해보았고, 각 화면마다 필요한 데이터가 생각보다 명확하게 구분됐다.
좌측 사이드바에서 사용되는 데이터 => 전체 글 목록
우측 편집 화면에서 사용되는 데이터 => 특정 글의 제목과 내용
또한, 좌측 사이드바에서 새로운 글을 생성하거나 특정 글을 선택한다면
=> 우측 편집 화면에서 그 글에 대한 제목과 내용을 보여줘야 하기 때문에, 이 둘 사이를 선택된 글의 id로 연결할 수 있겠다고 생각했고
=> 이를 최상위 컴포넌트인 App에서 state로 관리해준다면 각 컴포넌트들의 상호작용을 App에서 관리할 수 있겠다고 생각했다.
따라서, 전체적인 컴포넌트 구조를 다음과 같이 설계했다.
최상위 컴포넌트인 App 컴포넌트
state
: 선택된 글의 id인 selectedDocumentId
render()
: 전체 글 목록 documentList를 다시 불러와서 이를 SideBar 컴포넌트의 state로 전달해줌.좌측 사이드바에 해당하는 SideBar 컴포넌트
state
: 전체 글 목록인 documentList
하위 컴포넌트인 DocumentList 컴포넌트
state
: SideBar에서 전달받은 documentListrender()
: documentList에 따라 전체 글 목록을 그려줌우측 편집화면에 해당하는 EditPage 컴포넌트
state
: 선택된 글의 id인 selectedDocumentId
render()
: App의 selectedDocumentId가 변경될 때마다 state가 변경되고 그 때 마다 해당 글의 제목과 내용을 불러옴컴포넌트를 크게 App, SideBar, EditPage 이렇게 3 부분으로 나눴고, SideBar 안의 document 목록에는 포함되는 요소들이 많다고 판단해, SideBar 하위에 DocumentList 컴포넌트도 만들어주었다.
다음과 같은 흐름으로 컴포넌트들을 연결하려고 노력했다(실제로 이와 동일하게 구현하지는 못한 것 같다)
App에서 전체 state를 관리
=> 특정 컴포넌트의 이벤트 등을 통해 App의
state
가 변경되면=> 이에 따라 하위 컴포넌트들의
state
변경=>
state
변경됐으니render
를 통해 각 컴포넌트 화면 다시 그려주기
좀 더 구체적으로 노션 페이지의 전체적인 흐름을 상상해보면,
SideBar에서 전체 글의 목록을 확인하고 새로운 글을 생성하고 삭제할 수 있다.
선택된 글의 제목과 내용을 EditPage에서 확인할 수 있다.
SideBar에서 특정 글이 선택된다면 => App 컴포넌트에서 selectedDocumentId를 설정해주고 => EditPage에서 이에 따라 글의 제목과 내용을 보여줌.
=> 결국 컴포넌트 간의 상호작용을 App에서 관리하기 때문에, 공통된 data와 이 data를 다루는 메서드들은 App 내에 정의하고, 이러한 data과 메서드들을 다른 컴포넌트 생성 시 인자와 콜백함수로 전달해주었다.
노션 프로젝트를 진행하면서, 프론트 개발에 있어서 중요하고 앞으로 자주 구현하게 될만한 기능들을 구현해볼 수 있었다.
이렇게 특정 기능을 구현한 과정을 좀 더 자세히 정리해 나중에 비슷한 기능을 구현할 때 도움이 되도록 만들 생각이다.
프로젝트를 시작할 때, 컴포넌트 구조 설계를 고민하는 데에 많은 시간을 투자할 수록 개발 진행이 더 수월해지는 것을 느꼈다. 각 컴포넌트마다 가지고 있는 data와 할 일을 명확하게 정하고, 나누자. 그리고 컴포넌트 간 공유되는 데이터와 그 데이터를 어떻게 조작할 지도 생각하자.
각 컴포넌트 별로 공통적으로 state
, setState()
, render()
, init()
등의 메서드를 정의할 때, 이 data와 메서드들의 역할을 일관성있게 정하는 것이 중요하다고 느꼈다. 컴포넌트 별로 각 메서드가 어떤 역할을 할지 정하는 것도 중요하지만, 컴포넌트들에 공통적으로 정의되는 메서드라면 다른 컴포넌트에서도 동일한 결의 역할을 해야 헷갈릴 여지가 없겠다고 생각했다.
특정 컴포넌트에서는 setState()
가 state의 변경과 화면을 다시 그려주는 역할까지 담당하는데 다른 컴포넌트에서는 오직 state의 변경만 담당한다면, 통일된 구조가 없어 계속 헷갈릴 것이고, 이는 프로젝트의 볼륨이 커질수록 더 큰 문제가 될 것이다.
데브코스를 시작한 후 첫 프로젝트여서 그런지, 잘하고 싶은 마음이 컸고 그만큼 완성도 있게 만들고 싶어서 열심히 고민하고 또 노력했던 것 같다. 그래서 나에게는 애착이 많이 가는 프로젝트다.
노션 프로젝트를 진행하면서, "노션이라는 서비스가 가지고 있는, 또 가질 수 있는 기능이 굉장히 많을 수 있겠다"고 생각했고 이대로 프로젝트를 끝내는 것이 아니라, 내가 앞으로 학습하는 새로운 내용과 기술들을 이 프로젝트에 적용해보면서, 실제 노션 서비스와 비슷하게 또는 나만의 방식대로 발전시켜 나간다면 훌륭한 개인 프로젝트이자 나만의 개발 연습장이 되지 않을까 생각했다. 앞으로 이 프로젝트를 계속 다듬고, 발전시켜봐야겠다.
정리가 잘 된 글이네요. 도움이 됐습니다.