728x90
Next.js 13
app 디렉터리 등장
- /pages로 정의하던 라우팅 방식이 /app 디렉터리로 이동함
- 파일명으로 라우팅하는 것이 불가능해짐 => 폴더명까지만 주소로 변환됨
- layout.js
- 페이지의 기본적인 레이아웃 구성하는 요소
- 해당 폴더에 layout이 존재하면 그 하위 폴더 및 주소에 모두 영향을 미침
- 주소별 공통 UI 포함할 수 있음
- _app과 _document를 대신해 웹페이지를 시작하는 데 필요한 공통 코드를 삽입할 수 있음
- 단, layout예약어를 필수적으로 사용해야 함
- children을 props로 받아서 렌더링 해야함
- page.js
- layout을 기반으로 위와 같은 리액트 컴포넌트를 노출함
- error.js
- 해당 라우팅 영역에서 사용되는 공통 에러 컴포넌트
- 특정 라우팅별 서로 다른 에러 UI를 렌더링할 수 있음
- 에러 정보를 담고 있는 error 객체와 에러 바운더리를 초기화할 reset 함수를 props로 받음
- 단, 에러 바운더리는 클라이언트에서만 작동하기 때문에 error 컴포넌트 또한 클라이언트 컴포넌트여야 함
- layout에서 에러가 발생할 경우 error 컴포넌트로 이동하지 않음 => <layout><erorr>{children}</error></layout> 구조로 렌더링되기 때문
- not-found.js
- 특정 라우팅 하위의 주소를 찾을 수 없는 404 페이지를 렌더링할 때 사용
- loading.js
- 리액트 suspense를 기반으로 해당 컴포넌트가 불러오는 중임을 나타낼 때 사용함
- route.js
- REST API의 get, post와 같은 메서드명을 예약어로 선언해 두면 HTTP 요청에 맞게 해당 메서드를 호출하는 방식으로 작동함
리액트 서버 컴포넌트
- 기존 리액트 컴포넌트와 서버 사이드 렌더링의 한계 => 즉 리액트가 클라이언트 중심으로 돌아가기 때문에 발생하는 문제
- 자바스크립트 번들 크기가 0인 컴포넌트를 만들 수 없음
- 백엔드 리소스에 대한 직접적인 접근이 불가능함
- 자동 코드 분할이 불가능함 => 일일이 lazy로 감싸고 이를 기억해야 함
- 연쇄적으로 발생하는 클라이언트와 서버의 요청을 대응하기 어려움
- 추상화에 드는 비용이 증가함
- 서버 컴포넌트
- 하나의 언어, 하나의 프레임워크, 그리고 하나의 API와 개념을 사용하면서 서버와 클라이언트 모두에서 컴포넌트를 렌더링할 수 있는 기법을 의미
- 서버에서 할 수 있는 일은 서버가 처리하게 두고, 서버가 할 수 없는 나머지 작업은 클라이언트인 브라우저에서 수행
- 단, 클라이언트 컴포넌트는 서버 컴포넌트를 import 할 수 없음
리액트 컴포넌트
- 서버 컴포넌트
- 요청이 오면 그 순간 서버에서 딱 한 번 실행됨 => 상태를 가질 수 없음, 리액트에서 상태를 가질 수 있는 훅을 사용할 수 없음
- 렌더링 생명주기 사용할 수 없음
- effect나 state에 의존하는 사용자 정의 훅 또한 사용할 수 없음
- 브라우저에서 실행되지 않고 서버에서만 실행되기 때문에 DOM API를 사용하거나 window, document 등 객체에 접근할 수 없음
- 데이터베이스, 내부 서비스, 파일 시스템 등 서버에만 있는 데이터를 async/await 으로 접근할 수 있음
- 다른 서버 컴포넌트를 렌더링하거나 혹은 클라이언트 컴포넌트를 렌더링할 수 있음
- 클라이언트 컴포넌트
- 브라우저 환경에서만 실행되므로 서버 컴포넌트를 불러오거나, 서버 전용 훅이나 유틸리티를 불러올 수 없음
- 클라이언트가 자식으로 서버 컴포넌트를 갖는 구조가 가능함
- 공용 컴포넌트
- 서버와 클라이언트 모두에서 사용할 수 있음
- 서버 컴포넌트와 클라이언트 컴포넌트의 모든 제약을 받는 컴포넌트가 됨
서버 사이드 렌더링과 서버 컴포넌트의 차이
- 서버 사이드 렌더링
- 응답반은 페이지 전체를 HTML로 렌더링하는 과정을 서버에서 수행한 후 그 결과를 클라이언트에 내려줌
- 이후 클라이언트에서 하이드레이션 과정을 거쳐 서버의 결과물을 확인하고 이벤트를 붙이는 등의 작업 수행
- 초기에 인터렉션을 부가능하지만 정적인 HTML을 빠르게 내려주는 데 목적을 둠
- 서버 컴포넌트
- 서버에서 렌더링할 수 있는 컴포넌트는 서버에서 완성해서 제공받은 다음, 클라이언트 컴포넌트는 서버 사이드 렌더링으로 초기 HTML으로 빠르게 전달받을 수 있음
- 이러한 방식으로 하면 클라이언트 및 서버 컴포넌트를 모두 빠르게 보여줄 수 있고, 동시에 클라이언트에서 내려받아야 하는 자바스크립트의 양도 줄어 브라우저의 부담을 덜 수도 있음
서버 컴포넌트 작동 방식
- 서버가 렌더링 요청을 받는다. 서버가 렌더링 과정을 수행해야야 하므로 리액트 서버 컴포넌트를 사용하는 모든 페이지는 항상 서버에서 시작되
- 서버는 받은 요청에 따라 컴포넌트를 JSON으로 직렬화함. 이때 서버에서 렌더링할 수 있는 것은 직렬화해서 내보내고, 클라이언트 컴포넌트로 표시된 부분은 해당 공간을 플레이스홀더 형식으로 비워두고 나타냄. 브라우저는 이 후 결과물을 받아 다시 역직렬화한 다음 렌더링을 수행함
- 브라우저가 리액트 컴포넌트 트리를 구성함. 브라우저가 서버로 스트리밍으로 JSON 결과물을 받았다면 이 구문을 다시 파싱한 결과물을 바탕으로 트리를 재구성해 컴포넌트를 만들어 나감. 최종적으로 이 트리를 렌더링해 브라우저의 DOM에 커밋함
서버 컴포넌트의 작동 방식의 특별한 점
- 서버에서 클라이언트로 정보를 보낼 때 스트리밍 형태로 보내 클라이언트가 줄 단위로 JSON을 읽고 컴포넌트를 렌더링할 수 있어 브라우저에서는 되도록 빨리 사용자에게 결과물을 보여줄 수 있음
- 컴포넌트별로 번들링이 별개로 돼 있어 필요에 따라 컴포넌트를 지연해서 받거나 따로 받는 등의 작업이 가능함
- 서버 사이드 렌더링과는 다르게 결과물이 HTML이 아닌 JSON 형태로 보내짐
Next.js에서의 리액트 서버 컴포넌트
- 서버 컴포넌트는 클라이언트 컴포넌트를 불러올 수 없음
- 클라이언트 컴포넌트는 서버 컴포넌트를 children props로 받는 것만 가능
- 루트 컴포넌트는 각 페이지에 존재하는 page.js, layout.js이고, 모두 반드시 서버 컴포넌트여야 함
- getServerSideProps, getStaticProps, getInitialProps 삭제
- fetch API를 확정해 같은 서버 컴포넌트 트리 내에서 동일한 요청이 있다면 재요청이 발생하지 않도록 요청 중복 방
- 서버 : 렌더링이 한 번 끝날 때까지 캐싱
- 클라이언트 : 별도의 지시자나 요청이 없는 이상 해당 데이터를 최대한 캐싱
- 정적 렌더링과 동적 렌더링
- 정적 라우팅 : 기본적으로 빌드 타임에 렌더링을 미리 해두고 캐싱해 재사용할 수 있게 함
- 동적 라우팅 : 서버에 매번 요청이 올 때마다 컴포넌트를 렌더링하도록 변경
- fetch 옵션에 따른 작동 방식
- fetch(URL, { cache : 'force-cach' }) : 기본값으로 getStaticProps와 유사하게 불러온 데이터를 캐싱해 해당 데이터로만 관리
- fetch(URL, { cache : 'no-store' }) , fetch(URL, { next: {revalidate : 0}}): getServerSideProps와 유사하게 캐싱하지 않고 매번 새로운 데이터를 불러옴
- fetch(URL, { next: {revalidate : 10} }) : getStaticProps에 revalidate를 추가한 것과 동일하며, 정해진 유효시간 동안에는 캐싱하고, 이 유효시간이 지나면 캐시를 파기함
- revalidate
- 페이지에 revalidate라는 변수를 선언해서 정해진 시간 간격으로 갱신해 새로 렌더링 하게 됨
- 스트리밍을 활용한 점진적인 페이지 불러오기
- 하나의 페이지가 모두 다 완성될 때까지 기다리는 것이 아니라 HTML을 작은 단위로 쪼개서 완성되는 대로 클라이언트로 점진적으로 보내는 스트리밍 도입
- 모든 데이터가 로드될 떄까지 기다리지 않더라도 먼저 데이터가 로드되는 컴포넌트를 빠르게 보여주는 방법이 가능
- 사용자가 일부라도 페이지와 인터렉션 할 수 있음
- 최초 바이트까지의 시간 (TTFB), 최초 콘텐츠풀 페인팅(FCP)를 개선하는 데 도움됨
- 경로에 loading 배치
- suspense 배치
- 터보팩 등장
- 웹팩 대비 최대 700배, vite 대비 최대 10 빠르다고 함
- 서버 액션
- API를 굳이 생성하지 않더라도 함수 수준에서 서버에 직접 접근해 데이터 요청 등을 수행할 수 있는 기능
- 서버 컴포넌트와 달리, 특정 함수 실행 그 자체만을 서버에서 수행할 수 있다는 장점
- 최초에 페이지를 서버에서 렌더링한 이후에 폼에서 action으로 서버에 데이터 수정을 요청하고, 수정된 결과를 다시 조회해서 새로운 결과로 렌더링하는 모든 과정에 페이지 새로고침없이 수행할 수 있음
- form의 action
- action props를 추가해서 양식 데이터를 처리할 URI를 넘겨줄 수 있음
- input의 submit, image의 formAction
- startTransition과의 연동
서버 액션 사용 시 주의할 점
- 서버 액션은 클라이언트 컴포넌트 내에서 정의될 수 없음
- 서버 액션을 import하는 것뿐만 아니라, props 형태로 서버 액션을 클라이언트 컴포넌트에 넘기는 것 또한 가능함
728x90
'FE > 리뷰' 카테고리의 다른 글
[모던 리액트 딥다이브] 13장 웹페이지의 성능을 측정하는 다양한 방법 (2) | 2024.09.20 |
---|---|
[모던 리액트 딥다이브] 12장 핵심 웹 지표 (1) | 2024.09.18 |
[모던 리액트 딥다이브] 10장 리액트 17 vs 리액트 18 (1) | 2024.09.04 |
[모던 리액트 딥다이브] 9장 (2) | 2024.09.04 |
[모던 리액트 딥다이브] 8장 ESLint와 테스트 라이브러리 (3) | 2024.09.04 |