[5주차] Jobdri 구민교 & 이윤서 과제 제출합니다.#4
Conversation
| detail.original_name ?? | ||
| detail.title ?? | ||
| detail.name ?? | ||
| "Previews" |
| <div className="absolute top-[19.022px] left-1/2 h-[4.529px] w-[121.377px] -translate-x-1/2 rounded-[90.58px] bg-white" /> | ||
| </div> | ||
| </section> | ||
| ); |
| import React, { useState, useEffect } from "react"; | ||
| import Image from "next/image"; | ||
| import { useRouter } from "next/navigation"; | ||
| import { DotLottieReact, DotLottie } from "@lottiefiles/dotlottie-react"; | ||
|
|
||
| export default function NetflixLogoHandler() { | ||
| const router = useRouter(); | ||
| const [dotLottie, setDotLottie] = useState<DotLottie | null>(null); | ||
| const [logoState, setLogoState] = useState<"image" | "lottie" | "finished">( |
There was a problem hiding this comment.
혹시 여기 상태가 finished로 바뀌어도 로고 이미지 자체에는 아무런 변화가 없는 걸까요? 만약 맞다면, 아래 setTimeout함수 내부에 setLogoState는 사용하지 않으셔도 되는 것으로 보입니다.
There was a problem hiding this comment.
이미 구현이 완료되어 더 이상 참조되지 않는 페이지 관련 컴포넌트 폴더는 삭제해도 좋을 것 같습니다!
There was a problem hiding this comment.
이 아이콘도 ic_topten.svg로 아이콘 네이밍 컨벤션 맞춰주시면 일관성 있을 것 같습니당
| const IMAGE_BASE = | ||
| process.env.NEXT_PUBLIC_TMDB_IMAGE_BASE_URL ?? "https://image.tmdb.org/t/p"; | ||
|
|
There was a problem hiding this comment.
현재 주소 값이 MyListRow 등 여러 곳에서 중복 정의되어 있는 것 같습니다. 이 부분을 constants 파일로 분리하여 import해 사용하면 나중에 주소가 변경되더라도 한 곳에서만 수정하면 되니 훨씬 효율적일 것 같아용
|
|
||
| export async function getTopSearches(): Promise<TmdbTrendingItem[]> { | ||
| const headers = getTmdbHeaders(); | ||
|
|
||
| if (!headers) { | ||
| return []; | ||
| } | ||
|
|
There was a problem hiding this comment.
모든 API 함수에서 getTmdbHeaders를 호출하고 if (!headers) return [] 체크를 반복하고 있는데, 이를 커스텀 fetch 래퍼 함수 하나로 묶어보는 건 어떨까요? 공통 헤더 주입과 에러 처리를 한곳에서 관리하면 코드가 훨씬 간결해질 것 같습니다.
| // ⭐ 로고 이미지 클릭 핸들러 | ||
| const handleImageClick = () => { | ||
| setIsImageFading(true); // 이미지 페이드아웃 시작 | ||
|
|
||
| // 이미지 페이드아웃(500ms)이 끝난 후 로티로 교체 | ||
| setTimeout(() => { | ||
| setLogoState("lottie"); | ||
| }, 500); | ||
| }; |
There was a problem hiding this comment.
로티 애니메이션 실행 전에 페이드아웃을 적용 전환이 자연스럽게 느껴지게 한 점이 좋았습니다! setIsImageFading 상태와 setTimeout 을 활용해 전환 타이밍을 분리한 구조도 명확해서 읽기 좋았습니다.
…/landingPage Feat: 랜딩페이지 구현
🔗: 베포링크
느낀점 및 배운점 (민교)
이번 프로젝트를 진행하면서 Next.js를 처음 사용해 보았고, 외부 API를 연결해 데이터를 가져오는 작업도 처음 경험해 보았습니다. 이전에는 주로 정적인 화면을 만들거나 한 파일 안에서 기능을 구현하는 방식에 익숙했는데, 이번에는 페이지 구조, 컴포넌트 분리, 데이터 요청, 응답 처리 등 전체적인 흐름을 함께 고려해야 했습니다.
그러나 이번 과제에서 가장 크게 느낀 점은 협업 개발이 단순히 페이지를 나누어 작성하는 것이 아니라는 점이었습니다. 혼자 작업할 때는 하나의 브랜치에서 계속 코드를 작성하면 되었지만, 협업에서는 기능별로 브랜치를 나누고 각자의 작업 내용을 커밋한 뒤 다시 합치는 과정이 필요했습니다. 실제 코드를 작성하는 것만큼이나 브랜치 관리, 커밋 컨벤션, PR 작성, 머지 과정 등 협업을 위한 절차가 중요하다는 것을 알게 되었습니다. 처음에는 이런 과정들이 익숙하지 않아 단순 개발보다 더 어렵게 느껴졌습니다.
특히 여러 브랜치를 오가며 작업하는 것에 익숙하지 않아 어려웠습니다. 이전에는 한 브랜치에서 쭉 작업하면 되었기 때문에 브랜치를 나누는 이유를 깊게 생각해본 적이 없었지만, 이번 협업을 통해 기능 단위로 작업을 분리하는 것의 중요성을 이해하게 되었습니다.
main 브랜치로 머지하는 과정에서 충돌이 발생한 적이 있는데, 충돌이 발생한 파일을 확인하고 어떤 코드가 필요한 코드인지 판단한 뒤 정리하는 과정에서 많이 헤맸습니다. 충돌 해결은 단순히 표시된 부분을 지우면 되는 것이 아니라, 전체 코드를 이해하고 조심스럽게 처리해야 하는 작업이라는 점을 배웠습니다.
프로젝트 초기 세팅과 파일 구조를 파트너와 함께 정하는 과정도 처음 경험해 보았습니다. 어떤 폴더에 어떤 파일을 둘지, 컴포넌트를 어떻게 나눌지, API 관련 코드는 어디에서 관리할지 등을 정리해야 했는데, 혼자라면 제 방식대로 빠르게 정하고 넘어갔을 부분도, 서로가 이해할 수 있는 구조로 맞춰야 했습니다. 이 과정에서 일관된 컨벤션 규칙이 협업의 효율에 큰 영향을 준다는 것을 느꼈습니다.
또한 상대방의 작업에 피해를 주지 않기 위해 더 신중하게 작업하려고 했습니다. 커밋을 하기 전에는 불필요한 변경 사항이 포함되지 않았는지 확인하고, 브랜치를 이동할 때는 현재 작업 상태를 정리하려고 노력했습니다. 아직 익숙하지 않아 실수도 많았지만, 그만큼 협업에서는 작은 습관들이 중요하다는 것을 배웠습니다. 다음 프로젝트에서는 작업을 시작하기 전에 브랜치 전략, 커밋 메시지 규칙, 폴더 구조 등을 더 명확히 정하고 진행해야겠다고 느꼈습니다.
느낀점 및 배운점 (윤서)
제한된 일정 속에서 팀원과 호흡을 맞추며 협업의 물리적·심리적 밀도를 조율하는 과정이 쉽지만은 않았습니다. 특히 효율적인 커뮤니케이션을 위한 PR(Pull Request) 및 Issue 템플릿의 부재가 큰 아쉬움으로 남습니다.
초기에 컨벤션을 명확히 정의하는 '시스템 구축'의 중요성을 체감했으며, 이번 경험을 계기로 다음 프로젝트에서는 작업의 표준화를 선행하여 리소스 낭비를 줄이고 코드 퀄리티를 유지하는 데 집중할 계획입니다
Research Question
Review Questions
useState,useEffect,onClick같은 브라우저 상호작용 기능은 사용할 수 없음lazy loading과 Suspence
lazy loading: 처음부터 모든 코드를 불러오지 않고, 필요한 시점에 특정 컴포넌트 코드를 불러오는 방식
→
lazy로 불러온 컴포넌트가 아직 로딩 중이면 렌더링이 suspend되고, 이때Suspense가 fallback UI를 보여줍니다.Automatic Batching
Automatic Batching: 여러 개의 상태 업데이트를 하나의 렌더링으로 묶어 처리하는 기능
setTimeout,Promise, native event handler 등에서도 상태 업데이트가 자동으로 묶임setCount,setName이 각각 실행되지만 렌더링은 한 번만 발생Cocurrent Rendering
Cocurrent Rendering: React가 여러 렌더링 작업을 더 유연하게 처리할 수 있도록 해주는 내부 렌더링 방식
→ React가 화면을 그리는 중에도 더 급한 작업이 들어오면 기존 작업을 잠시 멈추고 중요한 작업을 먼저 처리할 수 있음
** 단, Concurrent Rendering은 개발자가 직접 동시성 렌더링을 실행하는 것이 아니라 React 내부에서 작동하는 기반이다. 개발자는
useTransition,Suspense,startTransition같은 API를 통해 이를 활용해야 한다.useTransition과 startTransition
seTransition과startTransition을 통해 업데이트 우선순위를 바꿀 수 있음예를 들어, 검색창에서 입력값은 즉시 반영되어야 하지만, 검색 결과 목록은 조금 늦게 바뀌어도 됨
→ 여기서
setInput(value)는 즉시 처리하고,setKeyword(value)는 조금 늦게 업데이트 가능→ 사용자가 입력할 때 화면이 덜 버벅이고, 무거운 렌더링 작업은 뒤로 미룰 수 있음
Streaming Server Rendering
React 18에서는 서버 렌더링에서도 Suspense를 더 잘 활용할 수 있음
기존 SSR은 서버에서 전체 HTML을 다 만든 뒤 클라이언트로 보내는 방식에 가까워 일부 데이터가 늦게 준비되면 전체 페이지 응답이 지연될 수 있었으나, React 18의 streaming server rendering은 준비된 부분부터 먼저 브라우저로 보내고, 늦게 준비되는 부분은 나중에 이어서 보낼 수 있게 해줌
예를 들어, 페이지 상단의 헤더와 기본 콘텐츠는 먼저 보여주고, 댓글 목록이나 추천 목록처럼 늦게 불러와도 되는 부분은 Suspense fallback으로 처리할 수 있음
→ 사용자는 전체 페이지가 완전히 준비될 때까지 기다리지 않고, 먼저 준비된 UI를 볼 수 있음