[Project] PostList 불러오기 기능 구현

young_pallete·2021년 8월 29일
2

no#tation

목록 보기
1/11
post-custom-banner

시작하며 🌈

최근에 다시 프로젝트를 시작하고 있어요!
제가 현재 교육을 듣고 있는 데브코스에서, 어느 정도 요구사항을 요구했었는데, 사실 제멋대로(?!) 프로젝트를 만들고 있답니다. 😅

그래도, 개인 프로젝트란 건 결국 자기가 커스터마이징하는 맛 아니겠어요!
(당연히 팀 프로젝트라면 팀 목적에 맞춰서 진행해야 되겠죠?!😆)

그래도, 프로그래머스 측에서도 역시 저희의 자생력을 길러주기 위해, 요구사항도 최소화해주신 부분이 보였어요. (꽤나, 감동했답니다!😄👍👍)

그렇다면, 이제 제 프로젝트를 하는 과정을, 글과 함께 남기도록 하겠습니다. 결국 남는 건 당시의 생각들을 담은 기록물이라고 생각하니까요.

본론 📃

일단 저는 Vanilla JS로 컴포넌트의 상태 관리를 통해 포스트를 저장하고, 삭제하는 일종의 노션을 만들고 있어요!

이름까지 지었는데, 이름은 no#tation으로 지었습니다.
일단 망설이지 말고 글을 쓰고 보자는, 저를 반성하게 하는 의미네요.😂😂😂😂 (변명하자면 최근에 너무 심적인 여유가 없었어요...!)
그래도 막상 짓고나니 애정이 생기네요!

디렉토리 구조

현재 디렉토리 구조는 다음과 같아요.

D:\NO-HESITATION
|   .eslintrc
|   .gitignore
|   .prettierrc
|   index.html
|   package-lock.json
|   package.json
|   
\---node_modules
\---src
    |   App.js
    |   index.js
    |   
    +---components
    |   |   PostForm.js
    |   |   SideBar.js
    |   |   
    |   \---common
    |           Header.js
    |           Input.js
    |           
    +---pages
    \---utils
            renderPosts.js
            storage.js

예전에 배웠던 대로, 그리고 알고 있던 대로 최대한 SPA 라이브러리와 비슷하게 구현하려 노력해봤습니다.

src 내 주요 폴더를 말씀드리자면

components: 렌더링 때 생성될 컴포넌트
components\common: 다른 데서도 공통적으로 쓰일 수 있는 컴포넌트
pages: 이후 라우팅될 때 렌더링 될 페이지 (아직 미구현했어요!)
utils: 갖다 쓰기 쉽도록 구현해놓은 함수들

로 일단 간단하게 구성을 해놨어요. 아직은 정~말 초창기라, 이후에 또 계속해서 업데이트될 것 같습니다!

index.js

SPA 애플리케이션처럼, index.html에 직접적으로 호출되는 단 하나의 자바스크립트 파일이에요. 여기서는 App만 연결시켜줍시다.

import App from './App.js';
new App({
  $target: document.querySelector('#app'),
});

app.js

일단 이렇게 Dummy Data들을 직접 붙였어요.
api를 직접 쓰기 전에 이렇게 테스트를 하면 좋다고 해서 해봤는데, 확실히 좀 더 어떻게 처리해야 할지가 잘 그려지는 것 같아요 :)

import PostForm from './components/PostForm.js';
import SideBar from './components/SideBar.js';

export default function App({ $target }) {
  new SideBar({
    $target,
    initialState: {
      username: 'jengyoung',
      documents: [
        {
          id: 1, // Document id
          title: '노션을 만들자', // Document title
          documents: [
            {
              id: 2,
              title: '블라블라',
              documents: [
                {
                  id: 3,
                  title: '함냐함냐',
                  documents: [],
                },
              ],
            },
          ],
        },
        {
          id: 4,
          title: 'hello!',
          documents: [],
        },
      ],
    },
  });

  new PostForm({
    $target,
    initialState: {
      title: '테스트합니다',
      content: '테스트 중이에요!',
    },
  });
}

그리고 이번 글은, 불러오기 기능만 구현하는 것이니 SideBar만 보자구요!

SideBar.js

여기서 저는 하위 컴포넌트 Header를 생각했어요.

  1. sideBar에서는 일단 유저가 쓴 글을 불러오지만
  2. 맨 위에는 유저의 이름이 나오는 Header가 있어야 할 것 같다는 생각에서였어요.
import renderPosts from '../utils/renderPosts.js';
import Header from './common/Header.js';

export default function SideBar({ $target, initialState }) {
  const $sideBar = document.createElement('nav');
  $target.appendChild($sideBar);

  this.state = initialState;
  this.setState = nextState => {
    if (this.state.username !== nextState.username) {
      header.setState(nextState);
    }
    this.state = nextState;
    this.render();
  };

  const header = new Header({
    $target: $sideBar,
    headerSize: 'h5',
    initialState: this.state.username,
  });

  this.render = () => {
    const { documents } = this.state;
    renderPosts($sideBar, documents);
  };

  this.render();
}

이 부분에선 결국 state가 바뀌면 헤더의 상태를 변경시키고, 다시 렌더링을 다시 하게 되는데, 렌더링하는 부분은 바로 Posts겠네요!
그렇다면 다음과 같은 구조의 데이터를 어떻게 렌더링시킬까 살펴볼까요?!

[
  {
    id: string,
    title: string,
    documents: [
      {
        id: string,
        title: string,
        documents: [
          ...
        ]
      },
      {
        ...
      }
    ]
  }
]

utils/renderPosts

저는 가장 직관적인 재귀를 사용했어요!
결국 쭉 들어갔을 때, 만약 documents가 내용물이 없으면 리턴을 시키고, 있으면 계속해서 추가시키는 방식이죠!

여기서 innerHTML을 쓸까도 싶었는데, 실제로 innerHTMLDOM을 조작하는 데 있어 비효율적이라는 것을 알게 되어, 최대한 createElement로 썼답니다.

export default function renderPosts($parentNode, nowDocuments) {
  if (!nowDocuments.length) return;
  nowDocuments.map(doc => {
    const $nowNode = document.createElement('h6');
    const { id, title, documents: nextDocs } = doc;
    $nowNode.dataset.id = id;
    $nowNode.textContent = title;

    $parentNode.appendChild($nowNode);
    renderPosts($nowNode, nextDocs);
  });
}

결과적으로 이를 돌려보면, 어떻게 나오는지 볼까요?

결과

아고, 아가들이 잘 딸려 나오네요!

마치며 🌈

일단 아직 좀 더 생각해둔 구현해야 할 요구사항은 좀 많아서 갈 길은 한~참 멀지만, 그래도 기록하면서 나아가보려 합니다.

누군가에게는 도움이 되는 글이기를.
나아가 저에게는 뿌듯함을 느낄 수 있는 발자취가 되길 바라며, 이상!

profile
People are scared of falling to the bottom but born from there. What they've lost is nth. 😉
post-custom-banner

0개의 댓글