Skip to content
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

KDT_정태욱_6_RE #79

Open
wants to merge 32 commits into
base: main
Choose a base branch
from
Open

KDT_정태욱_6_RE #79

wants to merge 32 commits into from

Conversation

peacepiece7
Copy link

Move App Challenge

결과물 보기 (https적용 안했습니다!)

❗ 필수

  • 영화 제목으로 검색이 가능해야 합니다!
  • 검색된 결과의 영화 목록이 출력돼야 합니다!
  • 단일 영화의 상세정보(제목, 개봉연도, 평점, 장르, 감독, 배우, 줄거리, 포스터 등)를 볼 수 있어야 합니다!
  • 실제 서비스로 배포하고 접근 가능한 링크를 추가해야 합니다.

선택

  • 영화 개봉연도로 검색할 수 있도록 만들어보세요.
  • 영화 목록을 검색하는 동안 로딩 애니메이션이 보이도록 만들어보세요.
  • 무한 스크롤 기능을 추가해서 추가 영화 목록을 볼 수 있도록 만들어보세요.
  • 영화 포스터가 없을 경우 대체 이미지를 출력하도록 만들어보세요.
  • 영화 상세정보 포스터를 고해상도로 출력해보세요. (실시간 이미지 리사이징)
  • 차별화가 가능하도록 프로젝트를 최대한 예쁘게 만들어보세요.
  • API 기본 사용법

완성하지 못한 부분 (문제점)

1. webpack-dev-sever의 hot reload기능을 사용하지 못했습니다.

서버에서 EMS와 CJS를 같이 사용하기 때문에 서버도 번들링을 해줘야합니다.

그래서 프론트 서버 번들링, 리액트 앱 번들링 총 두 번 번들링을 하게됩니다.

여기서 해결하지 못한 부분이 있습니다.

  1. webpack-dev-server는 번들링 결과를 캐싱하여 개발 서버를 제공해주는데
    webpack-dev-server로 프론트 서버를 번들링하여 결과물을 개발 서버를 제공해줄 수 있는 방법을 못찾았습니다.
  2. 프론트 서버와 프론트 리액트 앱 총 두개의 entry가 있는데 각각의 entry는 rules가 달라야합니다. entry마다 rules를 다르게 설정하여 번들링하는 방법을 찾지 못했습니다.

2. React 18의 Suspense를 사용하지 못했습니다.

React18의 Steaming SSR은 서버 컴포넌트의 랜더링이 비동기적으로 동작합니다.

이를 활용할 생각이였으나 해결하지 못한 부분이 있습니다.

  1. /detail 페이지로 요청이 들어올 떄, 서버에서 OMDB로 API를 보냅니다. 이떄 서버 컴포넌트는 로딩창(fallback)을 클라이언트에 제공하도록 만들고 싶은데 데이터 패칭 전략을 어떻게 해야할지 잘 모르겠습니다.

그래서 nextjs12 버전에서 SSR하는 방식으로 대체 해놓은 상태입니다.

- /scripts/build.js
  - react front app, front server 번들러입니다.
  - webpack을 사용했습니다.
- /server/*
  - 프런트 서버 입니다.
  - express, react를 사용했습니다.
- /src/*
  - react front app입니다.
- render.js로직을 크게 변경할 예정이라 변경 전 세이브용 커밋입니다.
- 서버 랜더링 시 StaticRouter, 클라이언트 hydration시 BrowserRouter를
  사용합니다.
- eslint, prettier 코드 포메팅 설정 추가
- tailwind 스타일 설정 추가
- 스타일 설정 관련 webpack 번들러 옵션 추가
- tailwind ssr되도록 구조 변경
  - public/main.css에서 랜더링 하던 구조를 -> build/main.css로 tailwind css가 번들링된
    파일을 서버에서 랜더링 하도록 변경
- ssr Suspense 연습 코드 추가
- 랜딩 페이지ssr로 서버에서 검색 csr으로 변경
- 랜딩 페이지react query로 infinite scrolling 부분 구현
- 전체적으로 포메팅, 주석을 정리했습니다.
Copy link
Member

@iamidlek iamidlek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨습니다.
다양한 스펙과 ssr로 구현해 해보신 부분이 좋았습니다.
commit도 컨벤션을 정하셔서 작성하신 것 같아서 좋았습니다.

단순한 ssr? 이 아닌 클라이언트쪽에서도
hydration된 후 csr되어야 할 내용, 필요한 내용을 나누어 가져오는 부분 등
설정이 쉽지 않은 것 같습니다.
레퍼런스도 많이 찾아 보신 것 같아서 좋습니다.
저의 경우는 실무에서 요구 사항이 없다보니 동향만 보고 있었는데
덕분에 찾아 보게 된 것 같습니다 .
https://github.com/DylanJu/react-pure-ssr 여기 레포의 설정도 도움이 될 것 같습니다.

src/App.jsx Outdated
path="/detail"
element={
<Suspense fallback={<Spinner />}>
<ErrorBoundary fallback={<Error />}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ErrorBoundary 가 Suspense를 감싸주어야 되지 않을까요?
Suspense 안에 있어도 결과가 같나요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

서버사이드 랜더링시 Spinner아니면 데이터가 입혀진(hydration하지 않은)HTML 초안을 랜더링하는데, HTML 초안은 서버쪽에서 처리해주기 떄문에 반드시 HTML을 파일 반환합니다.
그래서 순서에 상관이 없을 것이라 생각했고 hydration이후 생길 수 있는 에러만 ErrorBoundary에서 처리해주도록 작성하였습니다.
저는 이런 생각으로 순서를 신경쓰진 않았는데 ErrorBoundary는 예상하지 못한 에러만 잡아내는 곳이니까 ErrorBoundary 가 Suspense를 감싸는 형태도 좋을 것 같습니다. :)


const handleOnSubmitSearchForm = (e) => {
e.preventDefault()
onSubmitSearchForm(`s=${encodeURIComponent(text)}${year ? `&y=${year}` : ''}${genre ? `&type=${genre}` : ''}`)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

axios의 {params : ...} 를 이용하는 것도 편리할 것 같요

import React, { useMemo, useState } from 'react'
import PropTypes from 'prop-types'

function getYearOptions() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

외부로 잘 빼주신 것 같습니다.

const date = new Date()
let year = date.getFullYear()
const yearOptions = []
while (year >= 1985) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1985가 년도를 의미하긴 하겠지만
어떤 의미인지 변수명으로 관리하면 더 좋을 것 같아요.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 수정해놓겠습니다. :)

}
return () => document.removeEventListener('scroll', getScrollY)
}, [])
return [isBottom]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scorllend 이벤트 혹은 IntersectionObserver도 활용해 보시면 좋을 것 같습니다.

Comment on lines 43 to 46
movie = movie ? JSON.parse(htmlEntitiesDecoder(movie)) : ''
if (!movie) {
return <div>Empty plz check the movie</div>
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

movie에 대해 if문이 선행되면 파싱한 객체를 변수 선언해서 이용 할 수 있을 것 같습니다.

}, [isBottom])

return (
<Layout>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

각 페이지에서 동일한 layout을 사용한다면
App의 라우터를 감싸는 형태로 주어도 좋을 것 같습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants