learn 부분도 간단하게 잘 되어있는 것 같아서 집 갈 때 해보면 좋을 듯 내가 다 맞춰줌
어디까지 데이터를 채워서 보낼 것인가?
root 또는 src안에 pages/
로 각 페이지를 작성할 수 있다. 중첩된 구조로 routing도 가능하며 posts/[id]
와 같이 []
이용하여 dynamic routing도 가능
ssr을 지원하는 만큼 next js는 각 페이지를 pre-rendering하여 client로 전송한다. pre-rendering에는 두 가지 방식이 있다.
ssr은 사실 pre-rendering의 한 종류
두 가지 다 사용할 수 있으나 서버의 성능을 고려한다면 static generation을 사용하는 것이 더 좋다. 요청이 들어왔을 때 html을 렌더링 하는 과정이 빠지게 되니 그동안 다른 작업을 더 할 수 있기 때문이다. 자주 html에 변경이 발생해야하는 작업등에 SSR이 필요하다면 부분적으로 사용하는 방법도 있다.
의 경우 미리 렌더링을 해둬야하는데 이때 미리 렌더링 하고 싶은 서버의 데이터가 있다면 처리할 수있다. getStaticProps/Path
를 정의하면 된다.(production에서는 build타임에서만, dev에서는 매 요청마다 호출) 물론 client단의 데이터 fetching도 가능하다.
data Fetcing section에서 더 자세히 알아볼테지만 전체 형태는 아래와 같다.
function Component({ data }: Data) {
// data를 이용한 어떠한 렌더링
}
//////////// 이 함수는 build time과 data를 fetch 해줘야할 때 쓰인다 -> 정말 데이터를 props로 넣어주기 위한 것 ///////
export const getStaticProps : GetStaticProps = async () => {
// 일반적으로 데이터를 받아오는 과정은 비동기적으로 발생한다.
const res = await fetch(~~);
..
데이터 처리
..
return {
props: { // 위에서 정의한 props들을 가지는 객체로 반환
data
}
}
}
nextjs를 사용하지 않는 react 같으면 useEffect를 이용하여 parent컴포넌트에서 데이터를 받아와서 넣어주거나, 자체적으로 컴포넌트(페이지)가 로드 됐을 때 값을 받아오도록 할 수 있지만 결국 이 과정들은 client에서 실행되는 것들이기 때문에 값들이 서버에서 전송되는 html에는 포함되지 않는다.
next js에서 지원하는 dynamic path가 data를 가져오는데 쓰인다면(react-router-dom의 useParams()) getStaticPaths: GetStaticPaths
를 이용해서 getStaticProps: GetStaticProps
에 해당 dynamic path를 넘겨줄 수 있다. 이 때 paths 배열로 반환되는 모든 요소에 대해 SSG를 진행하게 되는데 반환되지 않은 값에 대한 페이지 요청이 들어왔을 때의 처리를 fallback 속성으로 정의해줄 수 있다.
위 두 함수는 모두 일반 컴포넌트가 아니라 pages에 독립적으로 작성되어야한다.
하지만 Static Generation의 특징을 잘 생각해봤을 때 이미 렌더링된 html을 받는 것이기 때문에 서버에서 이미 변경된 데이터에 대한 정보를 업데이트하지 못했을 수도 있다.
그래서 일반적으로 데이터의 변화가 빈번하게 일어나지 않는 부분에 대해서 Static Generation을 사용하게 되고 자주 변화가 생기느 부분은 client-side data fetching을 이용하게 된다.
그게 아니라면 SSR을 이용하면 된다. → 페이지의 로딩 자체가 좀 느려지지만 데이터의 변화는 잘 반영될 것이다.
위와 똑같이 data를 fetching해줘야하는 경우 getServerSideProps
를 사용한다. (방법은 getStaticProps
와 같다. getSPerverSidePaths
가 없는 이유는 이미 페이지를 요청할 때 정보가 포함되어있기 때문)
→ 이렇게 렌더링 된 html은 cache-control header를 정의해주는 경우에만 caching. cache를 이용하는 경우도 data updating을 신경써서 해줘야한다. 함수의 context파라미터의 res 객체(client로 페이지를 담아서 보내려고 준비해둔 응답객체)의 header를 정의할 수 있다.
export async function getServerSideProps({ req, res }) {
res.setHeader(
'Cache-Control',
'응답으로 보낸 페이지를 어떻게 caching하면 될지에 대한 조건'
)
...
SSG에서 이미 render된 페이지를 다시 빌드하지 않고도 update할 수 있게한다. getStaticProps의 반환값에 revalidate: number
를 추가하면 입력된 초마다 해당 페이지만 regeneration하도록 Trigger.
이는 이미 client로 새로 만들어진 페이지를 알아서 잘 전송해준다는 것은 아니다.
새로 들어오는 페이지 요청에 데이터가 업데이트된 페이지를 보낼 수 있게 하는 것
만약 CDN에서 자동 caching하게 만들었다면 CDN입장에서는 이미 cache 된 old html이 있으니 계속 그것만 보내주게 될테니 useCDN: false
로 지정해주어야 업데이트가 제대로 일어난다.
useEffect를 이용하거나 nextjs에서 data fetching을 위해 자체적으로 제공하는 SWR hook을 사용해도 된다(추천)
https://swr.vercel.app/docs/getting-started 와 무려 한국어도 있다!
next js에서는 img 태그 대신 사용할 Image 태그를 자체적으로 제공한다. img 태그를 확장한 것으로 이미지를 다룰 수 있는 추가적인 프로퍼티도 제공하며 최적화도 해준다.
사용하는 방식은 img 태그와 같다. 내부 static 파일을 import 하여 사용할 수도 있고 외부 주소를 이용하여 가져올 수도 있다. → 외부 주소를 사용할 경우에는 next.config.js에 해당 도메인을 등록해줘야 CORS할 수 있다. nextjs의 이미지의 로더는 불러온 이미지를 위한 url을 여러개 만드는데 각 url 마다 이미지 사이즈가 다양하여 얘를 srcset 안에 넣어주게 된다. 사용자가 자신에게 맞는 사진을 사용할 수 있도록 하는 것이다.
각 페이지 단위로 Priority를 설정해줄 수 있다. priority
프로퍼티를 설정하여 LCP가 빨리 발생하도록 한다.
이미지를 불러오는 과정이 느리면 자주 발생하는 것이 layout shifting, 말 그대로 없었던 이미지가 로드가 끝나 화면에 추가되면서 레이아웃이 밀리는 것이다. 이미지에 의한 layout shifting을 막기 위해서는 크기를 지정해주는 것이 제일 좋다. widht, heigth 로 값을 지정해주거나 layout 프로퍼티에 원하는 값을 할당하여 사용할 수 있다. 그래서 Image 태그를 이용하려면 필수적으로 값을 지정해줘야한다..(약간불편한디)
→ 특히 fill의 경우는 objectFit과 objectPosition 프로퍼티를 이용해 위치를 조절할 수 있다.
이외에도 img 태그에서 사용할 수 있는 속성들도 사용할 수 있다.
https://nextjs.org/docs/api-reference/next/image
그리고 static한 이미지들을 public 폴더에서 관리해야한다.
Image 컴포넌트를 거치지않고 그냥 img 태그를 이용하는 등의 방법으로 이미지를 로드하려면 사진 파일을 public 폴더 아래에 둬야 위치를 인지한다.
하지만 굳이 그러지 않는 이유는 next.js가 최적화도 잘 되고 이미지를 잘 다룰 수 있도록 컴포넌트를 만들어 놨기 때문이다. 만들어진 것을 알맞게 잘 사용하는 것도 중요.
https://nextjs.org/docs/api-reference/next/image
image에서 src를 설정할 수 있는 방법은 두 가지가 있다.
images : {
domains: ['도메인'],
}
어떤 주소를 입력하든 상관 없지만 두 방법의 차이는 1의 경우 사이즈를 꼭 지정해주지 않아도 사용가능하지만
2의 경우는 무조건 width+height 를 지정해주거나 layout=’fill’을 설정해줘야한다.
viewport라고 말하는게 브라우저의 전체 viewport가 아니라 이미지 기준이라는 것을 생각하면서 docs를 읽으면 좋을 것 같다. 그러니까 이미지의 parent container. 왜냐면 내가 처음 읽을 때 헷갈렸기 때문…
그동안 사용해온 속성과 다르지않다.
그래서 반응형 웹을 구성할 때 이미지를 적절히 이용하고 싶다면 layout을 이용해야 유연하게 이미지 사이즈를 조절할 수 있을 것이다. 하지만 layout을 이용하게 되면 parent값에 영향을 받게 돼서 결국 parent도 매번 설정 해줘야할 수도 있다. 그래서 아예 Image와 Image 컴포넌트를 div로 한 번 감싼 컴포넌트를 만들어서 이 div에 대한 크기를 조절하는 것이 좋을 것 같다. 물론 이렇게 이용하고 싶다면 static imported image를 이용해야한다.
미디어 쿼리를 이용하고 싶을때 유용하며 next/image가 생성하는 다양한 크기의 image srcset에서 해당 크기를 찾아올 수 있다. 이는 성능 향상에도 도움을 주게 되는데 원래같으면 실제 보여지는 크기와 상관없이 원본 이미지를 받아와야했다면 필요한 크기만을 가진 파일을 요청할 수 있으니 전송되는 파일 크기를 줄일 수 있는 것이다.
sizes="(min-width: 75em) 33vw,
(min-width: 48em) 50vw,
100vw"
위와 같이 표현할 수 있다.
eslint: https://nextjs.org/docs/basic-features/eslint
typescript: https://nextjs.org/docs/basic-features/typescript
npx create-next-app@latest --ts
# or
yarn create next-app --typescript
React 에서 타입을 제공하듯이 Next.js에서도 타입을 제공한다. → 잘 활용하면 좋음
pages/
내부에 nested한 파일 구조를 그대로 routing 해주는 기능이 있다.
bracket을 이용하여 나타낼 수 있다. react-router-dom의 :id
와같은 역할
컴포넌트 내부에서 dynamic routing된 path에 접근하고 싶을 때는 useRouter()를 사용하여 query를 받아올 수 있다. → 그니까 꼭 routing params 뿐만 아니라 쿼리로 전달된 query params들도 알아서 파악해서 같이 전달해준다.
// 'pages/post/[postId].js', '/post/1?user=my'
...
const router = useRouter();
console.log(router.query); // { postId: '1', user: 'my' }
...
이 값은 서버 렌더링시에는 비어있고 hydrate되면 값이 생긴다.
<Link>
를 이용해서 클라이언트에서 라우팅을 이용할 수도 있고 useRouter()
를 이용해서 script속에서도 라우팅할 수 있다.
서버에서 data fetching을 하는 함수를 호출하지 않고 페이지를 라우팅 하는 것.
url query등을 이용하여 값을 전달하고자 할 수도 있지만 그 값이 페이지에 반영되지 않는다.
하지만 같은 페이지 내에서만 작동 → query string을 다루기 위한 routing이라고 생각할 수 있다.
페이지를 새로고침하지 않고 route의 상태만 바꾼다.
실제 데이터베이스와 api통신을 할 수 있는 것처럼 next js 자체에서 API 라우팅을 이용한다. pages/api/ 폴더 내부에 스크립트들을 위치시키면 그 경로가 엔드포인트가 되고 요청 주소로 이용할 수 있다.
백엔드 서버와의 통신을 위한 테스트인가 했는데 아니다. next export(SSG)에서는 지원하지 않지만
클라이언트에서 직접 외부 데이터베이스에 바로 요청을 넣었던 것을 한번 거치게 만드는 작업 → 보안상의 이유도 있고 클라이언트에서 좀 더 입맛에 맞게 사용할 수도 있고 데이터를 중간 단계에 한 번 저장하는 작업을 진행할 수 있다. → 미들웨어?
기본적으로 same origin only가 기본 값이며 CORS를 해야한다면 추가적으로 헤더를 설정해줘야한다.
// api/ 에 위치하게되는 파일들은 이런식으로 요청에 대한 처리와 응답 객체를 작성할 수 있다.
export default function handler(req, res) { .... }
Path를 Dynamic하게 사용한 것 처럼 API Route도 Dynamic하게 사용할 수 있다.
next js에서 정의하는 production을 위해 해야할일을 정의해둔 것이 많지만 정리하면 아래와 같다.
→ next js뿐만이 아니라 어떤 것들이라도 production을 할 것이라면 확인해야할 필요가 있다.
https://nextjs.org/docs/advanced-features/compiler
전부를 정리하기엔 지금 당장 필요한건지 모르겠어서(그리고 다른 공부하고 싶은 것도 많고..) 일단 읽고 ..
babel-plugin-styled-component
를 이용하여 컴파일하게 된다. jest, relay 등도 지원하며 여러가지 컴파일 옵션들을 지정할 수 있다(console.~~ 구문 포함하지 않기 등등)const Dynamic = dynamie(() => import('어떤모듈path'), {
suspense: true; //를 쓸거라면 여기
});
...
<Suspense fallback={<Loading/>}>
<Dynamic/>
</Suspense>
...
const Dynamic = dynamie(() => import('어떤모듈path'), {
loading: () => <서스펜스를 쓸 수 없다면 loading 프로퍼티에../>
});
named exports된 모듈을 사용하고 싶다면 import가 반환하는 promise를 받아서 속성값처럼 접근 가능getServerSideProp
와 getInitialProps
를 가지고 있다면 SSR로, 그렇지 않다면 SSG로 생각하고 optimize_app.tsx
getInitialProps
를 이용하여 모든 페이지에 공통인 초기 props를 전달해줄 수도 있다._document.tsx