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

[이은지] 11장: Next.js 13과 리액트 18 #83

Merged
merged 2 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions 11장/이은지.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
- 11.1 app 디렉터리의 등장
- 레이아웃의 한계를 극복하기 위해 도입
- Next.js 12 버전까지는 여러 개의 페이지에 공통된 레이아웃을 추가하는 작업에 한계가 있었다. 모든 페이지가 각각의 물리적으로 구별된 파일로 독립되어 있었기 때문이다.
- 라우팅 정의 방식의 변화
- 폴더명이 라우팅이 되고, 폴더에 포함될 수 있는 파일명은 몇 가지 예약어로 제한된다. 파일명은 라우팅 명칭에 영향을 끼치지 못한다.
- 파일명
- layout.js
- 폴더의 하위 폴더 및 주소에 공통적인 레이아웃을 적용할 수 있다.
- 레이아웃 뿐 아니라 하위 페이지를 시작하는데 필요한 공통 코드를 삽입할 수도 있다.
- CSS-in-JS의 초기화는 \_document 대신 루트의 레이아웃에서 수행할 수 있다.
- layout 내부에서도 비동기 작업을 수행할 수 있다.
- 주의사항
- children을 props로 받아서 렌더링 해야 한다.
- export default로 내보내는 컴포넌트가 반드시 있어야 한다.
- page.js
- props
- params: 동적 라우트 파라미터 값
- searchParams: URLSearchParams
- 해당 값은 layout에서는 제공되지 않는다. 같은 페이지에서 search parameter만 변경될 경우 레이아웃을 리렌더링할 필요가 없기 때문이다. 따라서 search parameter에 의존적인 작업은 반드시 page 내부에서 수행해야 한다.
- error.js
- 라우팅 영역에서 공통으로 사용되는 에러 컴포넌트를 정의할 수 있다.
- 주의사항
- 에러 바운더리는 클라이언트에서만 작동하므로, error 컴포넌트도 클라이언트 컴포넌트여야 한다.
- 같은 수준의 layout에서 에러가 발생할 경우 에러를 잡을 수 없다. (Layout 하에 Error 컴포넌트가 렌더링되기 때문일 것이다.)
- not-found.js
- loading.js
- route.js
- `/pages/api`에 대한 app 디렉터리 내부의 지원
- 디렉터리가 라우팅 주소를 담당, 파일명은 route.js로 통일
- e.g. `/app/api/hello/route.ts`
- app/api 외에 다른 곳에서 route.ts 라는 파일명을 사용해도 api가 동작한다.
- route 의 함수들은 다음과 같은 파라미터를 전달 받는다.
- request: fetch Request의 확장본
- context: 동적 파라미터 객체를 포함
-
- 11.2 리액트 서버 컴포넌트
- 리액트 컴포넌트 + 서버 사이드 렌더링의 한계를 극복하기 위해 도입
- 일부 컴포넌트는 클라이언트에서, 일부 컴포넌트는 서버에서 렌더링하는 것.
- 서버 컴포넌트 / 클라이언트 컴포넌트 / 공용 컴포넌트
- 서버 컴포넌트
- 요청이 오는 순간 서버에서 딱 한 번 실행된다. 따라서 상태를 가질 수 없다. useState, useReducer 등 사용 불가
- 동일한 이유로 렌더링 생명주기도 사용할 수 없다. useEffect, useLayoutEffect 등 사용 불가
- DOM API, window, document 사용 및 접근 불가
- 서버에만 있는 데이터에 async/await로 접근할 수 있다. 컴포넌트 자체가 async한 것이 가능하다.
- 클라이언트 컴포넌트
- 서버 컴포넌트를 불러올 수 없다. 서버 환경이 없으므로 서버 컴포넌트를 실행할 수 없기 때문이다.
- 하지만 서버 컴포넌트가 클라이언트 컴포넌트를 렌더링할 때 클라이언트 컴포넌트의 하위에 서버 컴포넌트를 렌더링하는 구조는 가능하다. 클라이언트 컴포넌트 입장에서 이미 서버에서 계산된 트리를 삽입해서 보여주기만 하면 되기 때문이다.
- 리액트는 기본적으로 모든 컴포넌트를 공용 컴포넌트라고 판단한다. 즉, 모든 컴포넌트를 서버에서 실행 가능한 컴포넌트로 분류한다.
- 서버 사이드 렌더링 v.s. 서버 컴포넌트
- 서버 사이드 렌더링: 인터랙션 불가능한 정적인 HTML을 빠르게 내려주는 데 의의가 있다. 초기 HTML이 로딩된 이후에 클라이언트에서 자바스크립트 코드를 처리하는데 비용이 든다.
- 서버 컴포넌트: 컴포넌트 자체를 서버에서 렌더링
- 서버 컴포넌트의 작동 방식
- 서버가 렌더링 요청을 받는다. 이때 루트 컴포넌트는 항상 서버 컴포넌트다. (서버가 렌더링 과정을 수행해야 하기 때문)
logseq.order-list-type:: number
- 요청에 따라 컴포넌트를 JSON으로 직렬화(serialize)한다. 서버에서 렌더링할 수 있는 컴포넌트는 직렬화하고, 클라이언트 컴포넌트는 플레이스홀더 형식으로 비워둔다.
logseq.order-list-type:: number
- ## 직렬화된 데이터 예시
```json
M1: {"id":"./src/SearchField.client.js", "chunks": ["client5"], "name": ""}
M2:{"id":"./src/EditButton.client.js", "chunks": ["client1"], "name": ""}
S3: "react. suspense"
J0: ["$", "div",null,{"className": "main", "children": [["S", "section", null, {"className": "col sidebar", "children":[["$", "section", null,{"className": "sidebar-header", "children":[["$","img",null,{"className": "logo","src": "logo.svg", "width": "22px", "height": "20px- ", "alt":"'", "role": "presentation"}],["S", "strong",null,{"children": "React Notes"}]]}],C"$","- section", null,{" className": "'sidebar-menu, "role": "menubar", "children": [C"$", "Q1", null, C}],C"$" , "Q2", null, {"noteId" :null, "children": "New"}]]}],C"$", "nav", null, {"children": ["$", "$3", null, {"-
```
- M: Module, J: Json 이라고 하네요
- M: 클라이언트 컴포넌트
- J: 서버 컴포넌트
- 서버에서 렌더링되어 컴포넌트를 렌더링하는데 필요한 모든 element, className, props, children 정보가 들어가 있다.
- 나중에 렌더링되었을 때 들어가야 할 자식컴포넌트를 @1, @2 등 변수처럼 나타낸다.
- 브라우저는 서버로부터 스트리밍으로 JSON결과물을 받는다. 이를 파싱해 트리를 재구성하고 컴포넌트를 만들어나간다. 클라이언트 컴포넌트를 받으면 렌더링을 진행하고, 서버 컴포넌트를 받았다면 해당 정보를 기반으로 리액트 트리를 그대로 만든다.
logseq.order-list-type:: number
- 완성된 트리를 최종 렌더링해 브라우저의 DOM에 커밋한다.
logseq.order-list-type:: number
- 리액트 서버 컴포넌트 작동 방식의 특별한 점
- 클라이언트에게 스트리밍 형태로 JSON을 전달 → 유저에게 빠르게 결과물을 보여줄 수 있다.
- 컴포넌트별로 번들링이 되어 있다. → 필요에 따라 컴포넌트를 지연해서 받거나 따로 받는 등의 작업을 할 수 있다.
- HTML 대신 리액트 컴포넌트 구조 자체가 담긴 JSON 파일을 보낸다는 점
- 이로 인해 생기는 제약 사항: 서버 컴포넌트에서 클라이언트 컴포넌트로 props를 보낼 때 직렬화 가능한 데이터만 넘길 수 있다
- 11.3 Next.js에서의 리액트 서버 컴포넌트
- Next.js 13 버전부터 리액트 서버 컴포넌트를 지원
- app router의 page.js와 layout.js는 반드시 서버 컴포넌트여야 한다.
- 새로운 fetch 도입, getServerSideProps, getStaticProps, getInitialProps 삭제
- 모든 데이터 요청을 Next.js가 확장한 fetch로 처리
- 서버 컴포넌트 트리 내에서 동일한 요청이 있다면 재요청이 발생하지 않도록 처리가 되어있다. 렌더링이 한 번 끝날 때까지 fetch 요청에 대한 내용을 캐싱한다.
- fetch 옵션에 따른 작동 방식
- `fetch (URL, {cache:force-cache')`: 기본값. 불러온 데이터를 캐싱해 해당 데이터로만 관리한다.
- `fetch (URL, { cache: 'no-store' },) fetch(URL, { next: {revalidate: 0 } }):` 캐싱 없이 매번 새로운 데이터를 불러온다.
- `fetch (URL, { next: { revalidate: 10 } })`: 정해진 유효기간 동안 캐싱, 이후에 캐시 파기
-
- 데이터의 유효 시간을 정해두고 시간이 지나면 데이터를 불러와서 페이지를 렌더링하도록 할 수 있다.
- fetch의 두번째 인자로 `{next: { revalidate?: number }}` 설정
- 첫 요청 시에는 캐싱 데이터를 보여준다. 지정한 시간이 지나면 백그라운드에서 데이터를 불러와 캐싱 데이터를 갱신한다.
- 스트리밍을 통한 점진적인 페이지 불러오기
- 기존: 서버가 HTML 전체를 렌더링해서 내려주기 전까지는 페이지를 볼 수 없음. 페이지가 보여지더라도 하이드레이션 과정 전에는 인터렉션이 불가함.
- Next.js: HTML을 작은 단위로 쪼개 완성되는 대로 클라이언트에 전송. 데이터가 먼저 로드되는 컴포넌트를 빠르게 보여줄 수 있다.
- 활용법
- 경로에 loading 배치
- 직접 Suspense를 사용
- 11.4 터보팩의 두둥등장
- 서버 액션: API 생성 없이 함수에서 바로 서버에 접근해 데이터 요청 등을 수행할 수 있는 기능
- 함수 내부 또는 파일 상단에 `use server` 지시자 선언
- 이게... 뭐지... 멘붕...
Copy link
Member

Choose a reason for hiding this comment

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

image

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ개웃기네

- 11.7 Next.js 코드 맛보기
- getServerSideProps 대체
- getStaticProps 대체
- loading.tsx, Suspense
72 changes: 72 additions & 0 deletions 9장/이은지.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
- 9.1 Next.js로 리액트 개발 환경 구축하기
- 작성해야 하는 파일
- Node.js 프로젝트이므로 package.json
- 타입스크립트 사용을 위한 tsconfig.json
- `”$schema”: “https://json.schemastore.org/tsconfig.json`
- tsconfig 작성 시 자동 완성 가능해짐
- 옵션
- compilerOptions
- jsx: .tsx 파일 내부의 JSX를 어떻게 컴파일할지 설정
- react
- react-jsx, react-jsxdev
- preserve
- Next.js의 경우 swc가 JSX까지 변환해주기 때문에 preserve를 사용할 수 있다.
- 9.2 깃허브 100% 활용하기
- 깃허브 액션
- CI의 핵심: 저장소 코드에 변화가 있을 때마다 전체 소프트웨어의 정합성을 확인하기 위한 작업을 자동으로 실행. 필요한 작업은 테스트, 필드, 정적 분석, 보약 취약점 분석 등.
- 깃허브에서 일어나는 다양한 액션을 트리거로 사용자가 원하는 작업을 수행할 수 있도록 도와주는 서비스이다.
- 기본 개념
- 러너
- 깃허브 액션이 실행되는 서버. 지정하지 않을 경우 공용 깃허브 액션 서버를 이용한다. 자체적으로 별도의 러너를 구축할 수도 있다.
- 이벤트
- schedule: 특정 시간에 특정 작업을 실행할 수 있다.
- 브랜치에 머지 전 꼭 성공해야 하는 옵션이 있다면 저장소에서 브랜치 보호 규칙 추가하기
- 깃허브 Dependabot으로 보안 취약점 해결하기
- 의존성에 문제가 있다면 문제를 알려주고, 가능하다면 해결할 수 있는 PR까지 열어주는 깃허브의 기능. 프로젝트의 보안 위협을 제거할 수 있다.
- dependencies 이해하기
- 유의적 버전(semantic versioning)
- 버전은 주.부.수로 구성되어 있다.
- 주: 기존 버전과 호환되지 않게 API가 바뀌면 주 버전을 올린다.
- 부: 기존 버전과 호환되면서 새로운 기능을 추가할 때는 부 버전을 올린다.
- 수: 기존 버전과 호환되면서 버그를 수정했다면 수 버전을 올린다.
- 버그 수정이 API 스펙을 동원하는 경우 주 버전을 올려야 한다. 주 버전을 올리기 어렵다면 해당 API를 deprecated 처리하고, 새로운 API를 만들어 부 버전을 올리는 게 좋다.
- npm의 버전 규칙
- [email protected]: 정확히 16.0.0 버전에 의존
- react@^16.0.0: 16.0.0과 호환되는 버전. 16.0.0부터 17.0.0 미만의 모든 버전.
- react@~16.0.0: 패치 버전에 대해서만 호환되는 버전. 16.0.0부터 16.1.0 미만의 모든 버전.
- 유의적 버전은 개발자 간의 약속일 뿐, 그 자체가 실제 API가 유의적 버전에 맞게 구현되었다는 사실을 보장하지는 않는다. 하지만 버전을 보고 얼마나 중요한 변경사항이 있었는지를 짐작해볼 수는 있다.
- 가령 수 버전만 올라간 경우 단순 패치 수정일 것이므로 올리더라도 기능상에 큰 문제는 없을 것이다.
- 의존성
- npm 프로젝트를 운영하는데 필요한 자신 외의 npm 라이브러리
- peerDependencies
- 직접적으로 해당 패키지를 import하지는 않지만 호환성으로 인해 필요한 경우.
- 가령 커스텀 훅을 제공하는 패키지라면
- react를 만드시 import해야하는 것은 아니지만 *리액트 훅을 제공하는 버전을 설치한 서비스*에서 사용해야만 올바르게 사용할 수 있다. 이 경우 리액트를 peerDependencies로 선언한다.
- `npm ls [패키지명]`
- 패키지가 어디에 설치되어 있는지 확인할 수 있는 명령어. ls: list installed packages
- package.json의 overrides를 사용하면 패키지 내부에 선언된 의존성을 강제로 올릴 수 있다.
- dependabot이 경고하는 모든 문제를 해결할 필요는 없다. 시급성에 따라 대처하는 게 바람직하다. 그렇지만 관심 가지고 보기!
- 9.3 리액트 애플리케이션 배포하기
- Netlify, Vercel, DigitalOcean
- 다들 뭐 쓰시나요?
- 9.4 리액트 애플리케이션 도커라이즈 하기
- 도커
- 개념
- 서비스 운영에 필요한 애플리케이션을 격리해 컨테이너로 만드는데 이용하는 소프트웨어
- 애플리케이션을 이미지 상태로 준비해두면 이 이미지를 실행할 수 있는 환경 어디에서나 웹 애플리케이션을 배포할 수 있다.
- 도커는 애플리케이션을 ‘컨테이너’라는 단위로 패키징한다. 도커는 컨테이너를 바탕으로 독립된 환경에서 애플리케이션이 일관되게 실행할 수 있도록 보장해준다.
- 용어
- Dockerfile > `빌드` > 도커 이미지 > `실행` > 컨테이너
- 이미지: 컨테이너를 만드는데 사용되는 템플릿. “환경을 이렇게 구성해줘~“
- 컨테이너: 이미지를 실행한 상태. 완성된 환경. 이미지가 목표하는 운영체제, 파일 시스템, 각종 자원 및 네트워크가 할당되어 애플리케이션이 실행될 수 있는 독립된 공간.
- Dockerfile: 이미지 파일을 정의하는 파일. 이 파일을 빌드하면 도커 이미지를 만들 수 있다.
- 태그: 이미지를 식별할 수 있는 레이블 값
- ubuntu:latest가 뭔지 드디어 알았다…
- ubuntu는 이미지명, latest는 태그명
- 리포지터리: 이미지 저장소.
- 레지스트리: 리포지터리에 접근할 수 있게 해주는 서비스
- Dockerfile 작성하기
- `FROM node:18.12.0-alpine3.16`
- 이미지를 실행할 베이스 이미지를 설정할 수 있다.
- 도커 이미지 저장소에서 node:18.12.0, alpine3.16이라는 이미지를 가져와 사용하겠다는 뜻. 이 한 줄 만으로 운영체제 설치 과정 없이 운영체제를 사용할 수 있다.
- 이미지를 만든다 > 도커 저장소를 생성해 이미지를 업로드 한다 > 클라우드 플랫폼에서 도커 이미지를 실행한다.
Loading