-
Notifications
You must be signed in to change notification settings - Fork 38
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
[서버 사이드 렌더링 - 2단계] 마루(박규한) 미션 제출합니다. #61
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.
안녕하세요 마루! 코드를 읽어보니 고생한 흔적이 보이네요 ㅎㅎ
로컬로 받아서 실행해보니 정상적으로 동작하는것도 확인했어요!
다만 모달 페이지를 처음 접근한 후 모달창을 닫으면 URL이 그대로 남아있더라구요
제가 생각했을때는 영화 목록 페이지, 모달 페이지는 각각 다른 페이지로 생각이 들었고, 하이브리드 렌더링으로 처리하는 경우 모달이 닫히면 URL이 변경되면서 영화 목록 페이지로 이동되는게 자연스럽다고 생각을 해요. 그 이유는 모달을 닫은 후 새로고침을 하면 다시 모달페이지로 가는게 자연스러운 흐름은 아니라고 생각해요
1. 영화 상세보기 페이지 모달에서 같은 영화를 클릭했을 때 동작 오류
다른 크루들의 코드를 보니 HTML파일에 정의한 INITIAL_DATA 의 movieId값이 달라진 경우 useEffect
를 이용하여 데이터 패칭을 처리하도록 되어있더라구요!
저는 INITIAL_DATA가 한 번 사용이 되면 그 다음은 INITIAL_DATA를 사용하지 않고 다 서버로 데이터 요청하도록 처리했어요.
첫 접속시에는 서버에서 패칭된 데이터이기에 fresh 하다고 생각했고, 그 다음 동일한 컴포넌트가 다시 렌더링 되는 경우 데이터가 stale 하다고 판단하여 이런식으로 했어요 (살짝 Nextjs의 getServerSideProps 의 동작과 비슷하게 처리해보고 싶었어요)
2. window 객체 공유를 위한 스크립트 중복
저는 스크립트 태그를 객체라 생각하고 하나의 태그에 모든 데이터를 넣어줬어요,, ㅎㅎ
마루가 생각하기에 INITIAL_DATA
의 용도는 무엇이라 생각하나요??
어떻게 보면 INITIAL_DATA
SSR 시 서버가 패칭한 결과값을 저장하는데 사실 모두 HTML 엘리먼트에 반영되어 클라이언트에 전달해주기에 언뜻보면 필요없다고 생각이 들 수도 있을거 같은데 마루의 생각이 궁금하네용
3. 클라이언트 코드에서 API 요청
아하 서버에 /:movieId
가 있는 이유가 클라이언트에서 TMDB가 아닌 우리 서버를 프록시 서버로 쓰기 위해 사용되는거군요!
제가 생각하기에 이건 요구사항에 따라 다를거 같은데 우선 TMDB는 외부 서버이기에 클라이언트에서 TMDB로 바로 요청하여 처리하는게 대체로 좋을거 같아요!
그 이유는 우리 서버를 프록시 서버로 사용한다면 서버의 부하가 커질거고, 동일한 데이터 2중 요청이기에 불필요한 네트워크 트래픽 증가 그리고 TMDB 서버, 우리 서버 둘 중 하나라도 문제가 생긴다면 클라이언트측에 피해가 예상이 되며 디버깅이 조금 힘들어질 수 있다고 생각해요.
하지만 지금 마루가 해준 방식처럼 우리 서버를 프록시 서버로 사용하는 경우는 언제가 있을지 생각해본다면
- BFF 또는 MSA로 구성되는 경우 요구사항에 따라 SSR 서버로 요청하는게 더 적합할 수도 있다고 생각해요
- 만약 클라이언트측에서 TMDB 서버로 데이터 요청하기에 권한이 없는경우 (예를들어 CORS 문제가 발생하는 경우) SSR 서버에서 TMDB 서버의 응답을 받아 클라이언트에게 전달해주는 경우 사용할 수 있을거 같아요! - 그런데 이건 법적 문제도 있을거 같으니 알아서 처신해야해요.. ㅋㅋㅋㅋㅋㅋ
<title>영화 리뷰</title> | ||
</head> | ||
<body> | ||
<div id="root"></div> | ||
<!--${MODAL_AREA}--> | ||
</body> | ||
<!--${INIT_DATA_AREA}--> | ||
<!--${INIT_MODAL_DATA_AREA}--> |
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.
저는 INIT_DATA_AREA 이쪽에 모든 데이터를 다 넣어줬는데 마루는 각각의 데이터마다 따로 값을 넣어줬네요!
혹시 이렇게 한 이유가 있나요??
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.
함수를 분리하려다보니 이런 구조가 만들어진 것 같아요!
하나의 스크립트 내에서 2개의 데이터를 넣어주려면 renderMovieHome에서 분기처리하거나 함수로 안묶고 라우터단에서 처리하는 방법이 있을 것 같은데, 관심사 분리를 하고 싶어서 이렇게 처리했던 것 같아요 ㅎㅎ
router.get("/:movieId", async (req, res) => { | ||
const movieId = req.params.movieId; | ||
|
||
const movieInfo = await fetchMovieDetail(movieId); | ||
const movieDetail = parseMovieDetail(movieInfo); | ||
|
||
res.send(movieDetail); | ||
}); |
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.
SSR서버를 거쳐 API서버에 데이터를 요청할 때 사용하는 라우터입니다!
다르의 말을 빌리면 프록시 역할을 하는 라우터라고 생각하시면 될 것 같아요. 브라우저가 CSR로 데이터를 페칭할 때 SSR 서버의 해당 라우터에 요청을 보내 JSON 데이터를 받습니다. PR에도 작성한 것처럼 원하는 데이터만 파싱하는 과정을 SSR서버에서 해주기 때문에 브라우저는 정제된 데이터만 받을 수 있습니다!
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.
다르 꼼꼼한 답변 감사합니다:) navigate로 다시 돌아가는 생각 좋은 것 같아요! 이전 미션에서처럼 유지되는 게 요구사항이라고 생각해서 유지했는데, 돌아가는 게 자연스럽기도 하고 같은 영화를 클릭했을 때 생긴 문제도 해결되었네요!!!
마루가 생각하기에 INITIAL_DATA 의 용도는 무엇이라 생각하나요??
엇 하이드레이션 하기 위해선 필요하지 않나요?? 서버에서 window 객체로 넘겨준 데이터로 클라이언트(리액트)가 서버에서 넘겨준 HTML과 같은 트리구조를 그리기 위함이라고 생각합니다!
하이드레이션 이후에는 클라이언트단에서 다양한 로직을 처리하기 위해 넘겨준 데이터를 상태로 관리하여, 다양한 상호작용을 가능하게 만들 수 있을 것 같습니다!
다르 말대로 SSR서버로 보낼지 API 서버로 보낼지는 상황에 따라 다를 것 같긴 합니다! 여러 요구사항들을 따져봐야겠네요 감사합니다 😁😁😁
router.get("/:movieId", async (req, res) => { | ||
const movieId = req.params.movieId; | ||
|
||
const movieInfo = await fetchMovieDetail(movieId); | ||
const movieDetail = parseMovieDetail(movieInfo); | ||
|
||
res.send(movieDetail); | ||
}); |
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.
SSR서버를 거쳐 API서버에 데이터를 요청할 때 사용하는 라우터입니다!
다르의 말을 빌리면 프록시 역할을 하는 라우터라고 생각하시면 될 것 같아요. 브라우저가 CSR로 데이터를 페칭할 때 SSR 서버의 해당 라우터에 요청을 보내 JSON 데이터를 받습니다. PR에도 작성한 것처럼 원하는 데이터만 파싱하는 과정을 SSR서버에서 해주기 때문에 브라우저는 정제된 데이터만 받을 수 있습니다!
API 서버 응답값의 필드명이 바뀌었을 때 대응하기 쉽다는 장점도 있겠네용
<title>영화 리뷰</title> | ||
</head> | ||
<body> | ||
<div id="root"></div> | ||
<!--${MODAL_AREA}--> | ||
</body> | ||
<!--${INIT_DATA_AREA}--> | ||
<!--${INIT_MODAL_DATA_AREA}--> |
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.
함수를 분리하려다보니 이런 구조가 만들어진 것 같아요!
하나의 스크립트 내에서 2개의 데이터를 넣어주려면 renderMovieHome에서 분기처리하거나 함수로 안묶고 라우터단에서 처리하는 방법이 있을 것 같은데, 관심사 분리를 하고 싶어서 이렇게 처리했던 것 같아요 ㅎㅎ
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.
빠르게 리뷰반영까지 다 해줬군요 마루!
하이드레이션 하기 위해선 필요하지 않나요?? 서버에서 window 객체로 넘겨준 데이터로 클라이언트(리액트)가 서버에서 넘겨준 HTML과 같은 트리구조를 그리기 위함이라고 생각합니다!
앗 맞아요 INITIAL_DATA
를 어떻게 활용할 수 있을까를 생각하다보니 첫 렌더링 시 하이드레이션 하기위해 사용된다는 것을 잠시 까먹고 있었네요.. ㅎㅎ
요구사항을 모두 충족하고, 전체적으로 잘 만들어주어 approve 남기도록 할게요
마지막 미션까지 고생했어요 내일 최종 데모데이까지 화이팅~! 😄
안녕하세요 다르~! 두번째 만나네요 이번에도 잘부탁드립니다 😁
구현하는 데에는 크게 오래 안걸렸는데 고민되는 부분들이 몇가지 있어 질문이 좀 있네용 얼마 안남았으니 힘냅시다 🔥🔥🔥🔥🔥🔥
👀 리뷰를 통한 생각 나눔
1. SSR 환경에서 웹 브라우저는 어떤 과정으로 하이드레이션(hydration)을 진행하는지 상세히 서술하시오.
2. 다음 두 가지 상황의 동작 과정을 비교해 설명하시오.
사용자가 처음 영화 목록 페이지에 접속할 때는 HTML 데이터를 받고, 하이드레이션 후 상세 페이지로 이동 시에는 JSON 데이터를 받습니다.
사용자가 처음 영화 목록 페이지에 접속할 때
정적인 HTML
을 응답받는다.하이드레이션 후, 사용자가 영화 목록에서 특정 영화를 클릭하여 상세 페이지로 이동할 때
JSON 데이터
만 응답받아 데이터만 갈아끼워주는 작업이 이뤄진다.3. 다음 두 가지 상황의 동작 과정에서 라우팅의 차이점이 무엇인지 서술하시오.
사용자가
https://주소/detail/12345
와 같이 브라우저에 직접 입력한 뒤 페이지로 이동할 때하이드레이션 후, 사용자가 영화 목록에서 특정 영화를 클릭하여 상세 페이지로 이동할 때
사용자가 브라우저에 직접 입력할 때는 SSR 서버에 특정 영화 데이터가 포함된 HTML 파일을 응답받습니다. API 서버에 데이터를 요청하고, 브라우저에 HTML 파일을 응답하는 것은 SSR 서버입니다.
반면, 하이드레이션 이후 상세 페이지 이동은 JSON 데이터만 응답받아 컴포넌트 데이터를 갈아끼웁니다. 브라우저에서 SSR 서버에 요청하면 파싱된 상세 페이지 데이터만 JSON 데이터로 응답합니다. 이때 라우팅을 처리하는 것은 브라우저(리액트)고, API 요청과 JSON 데이터 응답하는 것은 SSR 서버입니다.
질문
1. 영화 상세보기 페이지 모달에서 같은 영화를 클릭했을 때 동작 오류
모달 띄워진 다음 다른 영화를 클릭했을 때는 동작하는데, movieId가 같은 영화를 클릭하면 동작하지 않고 있어요. MovieDetailPage의 useEffect 분기처리 문제인 것 같은데, 이를 어떻게 처리했는지 궁금합니다!
2. window 객체 공유를 위한 스크립트 중복
서버 사이드에서 홈화면을 렌더링하는 함수랑 모달을 렌더링하는 함수를 분리했는데 이랬더니 스크립트 태그가 2개 생기는 문제가 생기더라구요. 해결하는 방법은 renderMovieHome에서 스크립트 태그를 분기처리하는 방식인데, 이럴 경우 렌더링 함수를 분리하는 의미가 없어지는 것 같아요. 어떻게 분리하는 게 좋을까요?
3. 클라이언트 코드에서 API 요청
저는 모달을 띄울 때 클라이언트단에서 SSR 서버에 movieId를 넘겨주고, SSR 서버에서 API 서버에 요청을 보내는 형식으로 구현하였습니다.
고민했던 부분은 클라이언트에서 영화 상세 데이터를 응답받을 때
SSR 서버에 요청을 할지
와API 서버에 직접 요청을 할지
입니다. 저는 2번째 방식에서 1번째 방식으로 바꿨는데요! 필요한 데이터만 파싱하는 게 SSR 서버의 역할 중 하나라 생각했고, 서버 코드를 import 할 수 없는 환경의 경우 변경에 유연하게 대처하기 어려울 것 같다는 생각이 들었습니다. 이에 대한 다르의 생각이 궁금합니다!