-
Notifications
You must be signed in to change notification settings - Fork 31
[김수연] Sprint 9 #156
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[김수연] Sprint 9 #156
The head ref may contain hidden characters: "Next-\uAE40\uC218\uC5F0"
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
수연님 이번 미션도 수고 많으셨습니다 :)
리엑트는 어느정도 능숙하시니, 여유가 되신다면 심화요구사항도 진행해 보시면 좋을 거 같습니다 :) (next prefetch 혹은 RSC 활용)
넥스트 앱라우터로 바꿨습니다. gpt에게 물어보면서 폴더구조를 변경했지만 틀린 부분이 있을 수 있습니다. 지적해주면 고치겠습니다,
->
크게 문제는 없는데.. 라우팅이나 도메인과 관련되지 않는 부분은 app 폴더 밖으로 빼거나 괄호로 감싸주시는 것이 좋습니다~
https://nextjs.org/docs/app/getting-started/project-structure#route-groups-and-private-folders
next app router의 경우 폴더 구조나 레이아웃은 정말 일부에 불과합니다. 빠른 완성을 목표로 하는 프로젝트가 아니라 학습을 목표로 하는 미션이므로, 단순히 gpt를 활용해 적용하기 보다는 차근 차근 개념을 익혀 보시면 더욱 좋을 거 같아요 :) RSC는 뭔지, cache는 어떤 것들이 있는지, server action은 어떤 것인지 등 app router가 왜 나왔고 왜 쓰는지 보시면 좋을 거 같습니다. 또 app router를 넘어, next가 제공하는 다양한 렌더링 방식을 이해하시는 것이 더욱 중요하구요!
전체적으로 랜딩페이지 ~ 보드 페이지(board/page.tsx)까지 버튼 클릭시 이동이나 모든 페이지 이동에서 너무 많은 네트워크를 소비합니다. 어떤 점이 문제인지 + 실무에서는 어떤식으로 렉을 잡는지 궁금합니다.
-> 아마 prefetch 문제가 있을 거 같네요. 그냥 리엑트와는 다르게 next는 요청한 페이지만 우선 내려주고 viewport에 있는 Link를 통해서 다른 페이지 관련 리소스를 추가로 불러오게 됩니다. 다만 prefetch는 dev에서는 진행이 안 됩니다! 그래서 배포시 오히려 더 빨라질 수 있어요.
https://nextjs.org/docs/app/building-your-application/routing/linking-and-navigating#2-prefetching
실무에서는 개발자 도구에 네트워크탭, lighthouse, performance 탭을 통해 어떤 리소스를 받고 처리하는 데 오래 걸리는지 파악하실 수 있습니다 :)
|
|
||
| import styled from 'styled-components' | ||
|
|
||
| const Boards = () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
베스트 게시글 컴포넌트에는 베스트 데이터를만 넘기고, 게시글 목록에는 전체 API 응답을 넘기는 방식이었습니다.
이 방식이라면 useEffect를 한번만 호출해도 되겠다라고 생각해서 보드 페이지(board/page.tsx)에서 처음부터 구성하였습니다
하지만 이후에 무한 스크롤, 검색 기능 등을 구현하면서 결국 useEffect가 여기저기서 추가로 호출되는 상황이 되었고,
결과적으로 보드 페이지(board/page.tsx)에서 useEffect가 중복되어 총 6번 호출되는 구조가 되어버렸습니다.
그래서 지금은 API 호출 로직을 하나의 파일로 분리해서 커스텀 훅으로 만드는 방식도 고려 중이긴 한데, 결국 한 파일에서 6번 호출되는것은 변하지 않는다고 생각이 듭니다
혹시 이런 상황이라면 주강사님은 어떤 방식으로 구조를 구성하실지 궁금합니다. (한 파일(보드 페이지(board/page.tsx))에 처음부터 설계한게 잘못된 것인지, 멘토님은 그럼 처음부터 어떻게 설계하실건지 등)
->
저라면 한 파일에 놓지 않았을 거 같습니다.
우리가 좋은 코드를 쓰도록 노력 하는 이유는 결국에는 유지보수를 쉽게 하기 위해서입니다. 수정 사항이 생기면 코드를 쉽게 찾을 수 있어야하고 다른 곳에 영향 없이 쉽게 수정할 수 있어야 합니다. 그런데 여러 로직이 하나의 파일에 존재한다면, 로직이 뒤섞여 코드 파악하기도 어렵고 서로 영향을 줄 확률이 높아집니다. 따라서 관련 있는 코드끼리 모으고, 필요한 부분만 노출 시키는 것이 좋습니다.
지금 보면, 코드가 뒤섞여 있기도 하고 관련 코드가 여기저기 흩어져 있기도 합니다. 베스트 게시글 호출 로직과 상태 값, 그리고 전체 글 로직과 상태 값이 섞여 있죠. 게다가 전체 글은 호출을 정의하는 부분과 무한스크롤이 실행되는 부분이 또 분리되어있죠. 이 경우 파일을 넘나들며 무슨 일이 생기는지 찾으러 다녀야 합니다.
한 파일에서 상태와 로직을 관리하고 자식으로 내려주는 경우는 자식들이 상태 값을 서로 공유할 때 고려할 수 있을 거 같습니다. (이 경우도 조금이라도 복잡해지면 저는 상태 관리 라이브러리를 고려합니다)
또, 커스텀 훅도 같은 관점에서 봐주시면 좋습니다. 단순히 useEffect를 줄이는 것이 목적이 아니라, 같은 관심사의 코드를 모으고 가독성을 높여주는 역할을 합니다.
예를 들어, 작성해주신 디바운스를 보면,
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedSearchTerm(searchTerm)
}, 500) // <- 디바운스 지연 시간
return () => clearTimeout(timer)
}, [searchTerm])7~8 줄 정도 읽어 가며 어떤 코드인지 들여다보게 되죠.
이거를 같은 관심사를 가지는 상태 값과, useEffect를 모아서 커스텀 훅을 제작한다면,
function useDebouncedValue(value: string, delay: number) {
const [debouncedValue, setDebouncedValue] = useState(value)
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedValue(value)
}, delay)
return () => clearTimeout(timer)
}, [value, delay])
return debouncedValue
}
// ----
const [searchTerm, setSearchTerm] = useState('')
const [debouncedSearchTerm, setDebouncedSearchTerm] = useDebouncedValue(searchTerm)한 줄만 보고 아~ 디바운스된거구나~ 하고 읽고 넘어갈 수 있습니다. 또, 여기서 디바운스 관련된 부분 수정이 필요하다면 해당 훅 파일로 쉽게 찾아가서 관련 부분만 수정할 수 있겠죠!
결론은, useEffect 실행 횟수 자체보다도 관심사 분리 관점에서 접근해 보시면 좋을 거 같습니다. 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
수정 사항이 생기면 코드를 쉽게 찾을 수 있어야하고 다른 곳에 영향 없이 쉽게 수정할 수 있어야 합니다. 그런데 여러 로직이 하나의 파일에 존재한다면, 로직이 뒤섞여 코드 파악하기도 어렵고 서로 영향을 줄 확률이 높아집니다. 따라서 관련 있는 코드끼리 모으고, 필요한 부분만 노출 시키는 것이 좋습니다.
-> 라는 피드백을 통해 한 파일에서 불러오지 않고 커스텀 훅도 만들어 각각 따로 관리하도록 변경하였습니다. 차라리 처음부터 커스텀 훅을 만들었다면 한 파일에서 불러오는 일이 없을 것 같기도 합니다.. 커스텀 훅을 자주 이용해보겠습니다.(그래도 아직 어렵네요,,)
| // BestBoards에 관한 useEffect | ||
| useEffect(() => { | ||
| const timer = setTimeout(() => { | ||
| setDebouncedSearchTerm(searchTerm) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
디바운스를 신경 써주셨네요 👍👍
| }, [page, selectedOption, debouncedSearchTerm]) | ||
|
|
||
| // 선택/검색이 바뀌면 초기화 | ||
| useEffect(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
useEffect가 늘어나고 약간은 복잡하게 느껴진 이유는, 설계 문제를 넘어서 api 활용이 살짝 잘못 된 이유도 있습니다🤣
본래 무한 스크롤은 데이터가 더 존재하는지, 그리고 다음 데이터는 어떤 것을 가져와야 하는 지를 서버에서 판단해 주어야 합니다. 그래서 무한 스크롤은 page 기반이 아니라 cursor 기반으로 개발된 api를 활용하죠.
page 기반의 api로 무한 스크롤을 개발하다보니, 부수적인 로직들이 더 생겨난 거 같습니다..! 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
그런데 지금 보니 디자인 시안이 애매하게 되어 있군요.. 😠
지금 같은 경우 실무 였다면, 디자인, 백엔드 둘 중 하나는 잘못 한 거로 판단하고 미팅 소집했을 거 같습니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저도 사실 cursor 없는거 보고 어떻게 하나 싶었는데.. 일단 무한 스크롤을 하고 싶어서 이 코드는 그대로 두었습니다..!
| const handleButton = () => { | ||
| if (fileInputRef.current) { | ||
| // if문을 쓰는 이유는 useRef 값이 null일 수도 있기 때문문 | ||
| fileInputRef.current.click() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
중요하지는 않지만.. 이렇게 할 수 도 있겠네요!
fileInputRef.current?.click()
| justify-content: space-between; | ||
| flex-direction: column; | ||
| ` | ||
| const ImageInput = styled.input` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
html hidden 속성을 쓸 수 있어요!
<input hidden/>
| import { textStyle } from '../styles/textStyle' | ||
| import Image from 'next/image' | ||
|
|
||
| const ButtonImage = () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
컴포넌트명이 약간 애매합니다 🤣
사실상 버튼이라기보다는 Input에 가깝죠!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
폴더명 자체가 경로가 되므로 폴더명은 소문자로 통일시켜준느 것이 좋겠네요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
제 파일에서는 소문자로 잘 되어있었는데 푸쉬할 때 같이 안 올라간 것 같습니다.. 그래도 전체적으로 검토 했습니다
| word-break: keep-all; | ||
| } | ||
| body { | ||
| overflow-y: hidden; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
body에 overflow가 hidden이라 화면이 잘려보입니다!
| @@ -0,0 +1,31 @@ | |||
| import { createGlobalStyle } from 'styled-components' | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FOUC 현상이 있어요! 스타일드 컴포넌트 같은 css in js는 next랑 상성이 안 좋습니다. FOUC에 대해 찾아보시고, 해결하는 방법도 알아보시면 좋을 거 같아요 :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이건 전혀 몰랐습니다.. css는 취향차이라고 생각했고 스타일컴포넌트가 좋아서 썼던 것인데 알아보니 앱라우터는 서버기반이고 스타일컴포넌트는 클라이언트 기반이라 서로 상성이 안 좋은거였다는 것을 멘토님을 통해 알았습니다 (피드백 수정하면서도 빌드 에러났습니다,,, )
sass로 변경해보겠습니다!
요구사항
기본
심화
주요 변경사항
넥스트 앱라우터로 바꿨습니다. gpt에게 물어보면서 폴더구조를 변경했지만 틀린 부분이 있을 수 있습니다. 지적해주면 고치겠습니다,
스크린샷
<태블릿>
<모바일>
멘토에게
무한 스크롤도 넣었습니다,
전체적으로 랜딩페이지 ~ 보드 페이지(board/page.tsx)까지 버튼 클릭시 이동이나 모든 페이지 이동에서 너무 많은 네트워크를 소비합니다. 어떤 점이 문제인지 + 실무에서는 어떤식으로 렉을 잡는지 궁금합니다.
보드 페이지(board/page.tsx)에서 useEffect가 총 6번 호출되고 있습니다.
처음에는보드 페이지(board/page.tsx)에서 API를 호출하고, 그 데이터를 자식 컴포넌트에 props로 넘겨주는 방식으로 설계했습니다.
베스트 게시글 컴포넌트에는 베스트 데이터를만 넘기고, 게시글 목록에는 전체 API 응답을 넘기는 방식이었습니다.
이 방식이라면 useEffect를 한번만 호출해도 되겠다라고 생각해서 보드 페이지(board/page.tsx)에서 처음부터 구성하였습니다
하지만 이후에 무한 스크롤, 검색 기능 등을 구현하면서 결국 useEffect가 여기저기서 추가로 호출되는 상황이 되었고,
결과적으로 보드 페이지(board/page.tsx)에서 useEffect가 중복되어 총 6번 호출되는 구조가 되어버렸습니다.
그래서 지금은 API 호출 로직을 하나의 파일로 분리해서 커스텀 훅으로 만드는 방식도 고려 중이긴 한데, 결국 한 파일에서 6번 호출되는것은 변하지 않는다고 생각이 듭니다
혹시 이런 상황이라면 주강사님은 어떤 방식으로 구조를 구성하실지 궁금합니다. (한 파일(보드 페이지(board/page.tsx))에 처음부터 설계한게 잘못된 것인지, 멘토님은 그럼 처음부터 어떻게 설계하실건지 등)