[TIL] Notion Clone Project 2일차

kcm dev blog·2021년 9월 5일
0

TIL

목록 보기
11/19
post-thumbnail

구현하기

어제의 설계를 바탕으로 구현을 시작했다. 컴포넌트의 역할을 명확히 나눴기에 순서를 꼭 구분지을 필요는 없으나, 구현을 함에 있어서 결과값이 금방 드러나는 것, 다른 컴포넌트를 구현하고 결과를 확인할 때 가장 도움이 될 컴포넌트들을 먼저 만드는게 더 좋을것 같아서 순위를 정했다. 그 결과 가장 먼저 구현한 것은 Navigation 이었다. Navigation을 먼저 구현해야 나중에 있을 Editor의 CRUD를 관리하기 쉬울 것 같다고 판단했기 때문이다.

Navigation의 자료구조 선정이 초반에 좀 까다로웠다. 단순하게 나열만 하면 상관 없지만, CRUD를 지원해야 하고, 하위 목록 숨기기/보이기 기능을 구현해야 하기 때문이다. (요구사항에 필수로 구현해야 하는 것은 아니나 노션의 특성상 숨기기/보이기 기능을 지원하기 때문에 이 기능은 사실상 필수 구현사항이라 생각했다) 또한 API response로 받은 데이터의 구조가 도큐먼트의 속성에 하위 도큐먼트 정보가 포함되어 있는 형태였기 때문에 적절한 자료구조를 선택하는데 애를 먹었다. Carot 클릭을 통한 숨기기/보이기, 제목 클릭을 통한 도큐먼트 열기, + 클릭을 통한 하위 도큐먼트 생성, X 클릭을 통한 도큐먼트 삭제 .. 이 기능들을 모두 아우를 수 있는 형태이어야만 하기에 구조를 짜는데 1시간은 걸렸던 것 같다.

고심의 결과 적절한 구조가 나왔다.

function renderDocumentTree(documents) {
  if (documents.length === 0)
    return NO_PAGE
  return `
      <ul class="doc-ul" >
        ${documents.map(doc => `
          <div class="doc-row" id="row${doc.id}">
            <span class="doc-carot" id="${doc.id}"><i class="fas fa-caret-right"></i></span>
            <span class="doc-title" id="${doc.id}">${doc.title}</span>
            <button class="doc-delButton" id="delBtn${doc.id}">x</button>
            <button class="doc-plusButton" id="plusBtn${doc.id}" >+</button>
          </div>
          <li id="sub${doc.id}" style="display: none">${renderDocumentTree(doc.documents)}</li>
        `).join('')}
      </ul>
    `
}

도큐먼트의 속성중 하위 도큐먼트 정보를 담고 있는 속성을 제외한 나머지는 div안에 묶고, 하위 도큐먼트는 li태그를 쓴다. 그리고 li의 값인 하위 도큐먼트도 상위 도큐먼트와 똑같은 형태이기 때문에 이를 해결하기 위해 재귀 용법을 사용했다.

그 결과, dummy data를 잘 파싱하여 요구사항에 맞게 랜더링이 이뤄졌다. 기능이 잘 작동함을 확인했고, editor component가 있어야 navigation component의 CRUD를 확인할 수 있기 때문에 dummy data를 읽는 방식을 유지하였다.

Editor

Editor component를 구현하는 것은 Navigation에 비해 쉬운 편이었다. 고려해야할 사항이 많지 않았기 때문이었다. Navigation 컴포넌트와의 연동성 확인을 위해 우선은 Create, Read 기능만 먼저 구현하였고, 무난하게 완성하였다.

다만 요구사항에 있던 자동완성 기능이 난이도가 꽤 있었다. 수업 시간에 배운debounce 기법을 활용하면 쉽게 구현 가능하지만, 이 원리를 알고, 직접 구현할 수 있어야 진짜 내것이라 생각했기에 원리만 파악하고 나머진 직접 구현하고 디버깅 해보면서 문제를 해결했다.

추가적으로 서버에 저장이 완료되면 저장 완료 메시지도 나타나도록 구현했는데 이전에 있던 멘토링 시간에 프론트엔드에는 피드백이 중요하다는 말이 떠올라서 추가하였다. 방식은 velog 자동 완성 기능을 차용했는데 Put 기능을 구현하고, 작동여부를 점검하는데 유용하게 쓰였다.

onEditing: (post) => {
      if (timer != null) {
        clearTimeout(timer)

      }
      // debounce 기법을 활용하여 서버에 실시간 저장(2초동안 입력 없는 경우)
      timer = setTimeout(async () => {

        saveDocInLocalStorage(post)
        await saveDocInServer(post)
        showMessage(post, $modal) // 이용자에게 server저장 여부 피드백
        

        // 전체 status update
        const _documentTree = await request('', {
          method: 'GET'
        })
        const title = getItem('meta').title
        const content = getItem('content')
        this.setState({
          ...this.state,
          documentTitle: title,
          documentContent: content,
          documentTree: _documentTree
        })
      }, 2000)
    }
profile
오늘 배운건 오늘 소화하자!

0개의 댓글