HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
👻
개발 기록
/
📑
강의 정리
/
📑
고양이 사진첩 만들기
📑

고양이 사진첩 만들기

Created
Sep 9, 2021 04:45 AM
Type
VanillaJS기본역량강화
Mento
로토
Created By

요구사항

  • 고양이 사진 API를 통해 사진과 폴더를 렌더링합니다.
  • 폴더를 클릭하면 내부 폴더의 사진과 폴더를 보여줍니다.
    • 현재 경로가 어딘지도 렌더링 합니다(브레드 크럼).
  • 루트 경로가 아닌 경우, 파일 목록 맨 앞에 뒤로가기를 넣습니다.
  • 사진을 클릭하면 고양이 사진을 모달창으로 보여줍니다.
    • esc를 누르거나 사진 밖을 클릭하면 모달을 닫습니다.
  • API를 불러오는 중인 경우 로딩 중임을 알리는 처리를 합니다.

요점 정리

notion image
  • App.js : 모든 컴포넌트를 관리함.
  • Breadcrumb.js : 목록의 자취를 보여줌.
  • Nodes.js : 노트 타입에 따라 폴더, 파일을 보여줌.
  • ImageView.js : 클릭한 이미지를 관리함.
  • Loading.js : API가 호출될 동안 로딩 중임을 알려줌.

API 호출

  • App.js에서 fetchNodes라는 함수를 만들어 파라미터로 id를 전달받으면 id에 맞는 노드를 반환함.
  • 현재 상태에서 반환받은 값을 포함하여 setState함.
  • 이때 isRoot를 확인하여 id가 있다면 false를, 없다면 true를 반환하게 만들어 root의 값을 알아낼 수 있음.

파일 이동 구현

  • Node 컴포넌트 생성자에 onClick 함수를 만들어 node의 type(directory/file)에 따라 노드의 id에 맞는 폴더를 보여줄지, 파일을 보여줄지를 결정함.
const nodes = new Nodes({ $target, initialState: { isRoot: true, //뒤로가기 넣을지말지 결정 nodes: [], }, onClick: async (node) => { if (node.type === "DIRECTORY") { await fetchNodes(node.id); } if (node.type === "FILE") { this.setState({ ...this.state, selectedImageUrl: `https://cat-api.roto.codes/static${node.filePath}`, }); } }, });
  • Nodes.js에서는 root인지를 판별해 뒤로가기 버튼을 만들어주고, nodes를 map으로 순회하며 파일, 폴더에 맞는 이미지를 innerHTML해줌.
  • addEventListner로 클릭했을 때 node의 id를 알아내어 onClick의 파라미터로 전달함.

Modal 구현

  • onClose를 클릭 시 콜백함수로 전달함.
  • onClose는 선택된 이미지 url을 null로 setState함.
window.addEventListener("keyup", (e) => { if (e.key === "Escape") { onClose(); } }); $imageViewer.addEventListener("click", (e) => { if (Array.from(e.target.classList).includes("Modal")) { onClose(); } });

뒤로 가기

  • 뒤로가기는 폴더 경로를 기억하고 있어야 함.
  • App.js this.state로 paths라는 항목을 만들어 뒤로갈 경로를 쌓음 → onClick할 때마다 paths.push(node)
  • node가 없을 때 onPrevClick함수가 호출될 수 있게 만듦.
  • onPrevClick은 paths.pop을 하여 경로를 뺀 후, paths의 길이에 따라 root를 fectch할지, 마지막 paths의 id를 fetch할지 결정함.

로딩 처리

  • Loading.js에서 isLoading 상태에 따라 display값을 block 또는 none으로 지정함.
  • App.js에서 컴포넌트 생성자를 만듦.
  • fetchNodes 함수가 호출될 때 setState로 isLoading을 true로 변환 후, 함수 마지막 부분(fetch가 완료되었을 때) false로 상태를 변경.
  • App.js의 setState에 loading.setState(this.state.isLoading);값을 추가함으로써 Loading 컴포넌트가 해당 값에 따라 로딩중임을 표시할 수 있게 만듦.

Breadcrumb 만들기

  • Breadcrumb.js에서 root와 함께 map으로 이름을 innerHTML로 그림.
this.render = () => { $breadcrumb.innerHTML = ` <div>Root</div> ${this.state.map(({ name }) => `<div>${name}</div>`).join("")} `; };
  • App.js에서 breadcrumb 컴포넌트를 만들고 setState에 breadcrumb.setState(this.state.paths);를 함(로딩바와 같은 원리).
  • 클릭했을 때 바로가기 만들기 : breadcrumb 컴포넌트에 onClick: (id) => {fetchNodes(id);}
  • 이때 root 등 이전 경로를 클릭했을 땐 path를 다시 렌더링하여 이전에 표시된 경로를 지워주어야 함.
//onClick 내부 if (id) { const nextPaths = id ? [...this.state.paths] : []; const pathIndex = nextPaths.findIndex((path) => path.id === id); this.setState({ ...this.state, paths: nextPaths.slice(0, pathIndex + 1), }); } else { this.setState({ ...this.state, paths: [], }); }
💡
컴포넌트끼리 유기적으로 움직이게 만들면, 매번 같은 코드를 만들필요 없이 컴포넌트의 큰 흐름에 합류시키기만 하면 됨.