Next.JS 2
많은 사람들이 Next.JS 이용 할 때 따르는 아주 흔한 패턴:
custom app component 사용할 때 쓰는 Layout component
_app.js 에는 global.css, 구글 어널리스틱, 스크립트 분석등 큰 일들을 처리하고
구조에대한 것은 layout component에 만든다.
Layouts
React 모델을 사용하면 페이지를 일련의 컴포넌트로 분해할 수 있습니다. 이러한 컴포넌트 중 많은 부분이 페이지 간에 재사용되는 경우가 많습니다. 예를 들어 모든 페이지에 동일한 navigation과 footer가 있을 수 있습니다.
https://nextjs.org/docs/basic-features/layouts
Head (next/head)
페이지 head에 엘리먼트를 추가하기 위한 내장 컴포넌트를 노출합니다.
< Head>
< title>My page title< /title>
</Head>
useEffect(() => {
(async () => {
const { results } = await (
await fetch(
`https://api.themoviedb.org/3/movie/popular?api_key=${API_KEY}`
)
).json();
setMovies(results);
})();
}, []);
()() 를 작성하는 부분이 궁금해서 찾아봤는데, IIFE (즉시 실행 함수 표현, Immediately Invoked Function Expression) 이라고 찾았습니다. 첫번째 괄호는 익명함수를 감싸 실행 될 함수가 전역 스코프에 불필요한 변수를 추가하거나, IIFE 내부안으로 다른 변수들이 접근하는 것을 막을 수 있는 방법이라고 설명되어 있습니다. 두번째 괄호는 즉시 실행 함수를 생상하는 괄호이고, 이를 통해 자바스크립트 엔진은 함수를 즉시 해석해서 실행한다고 설명되어 있습니다.
api키 숨기기
next.config.js
Next.js에서 커스텀 설정을 하기 위해서는 프로젝트 디렉터리의 루트(package.json 옆)에 next.config.js 또는 next.config.mjs 파일을 만들 수 있습니다. next.config.js는 JSON 파일이 아닌 일반 Node.js 모듈입니다.
Next.js 서버 및 빌드 단계에서 사용되며 브라우저 빌드에는 포함되지 않습니다.
https://nextjs.org/docs/api-reference/next.config.js/introduction
Redirects (URL변경됨)
Redirect을 사용하면 들어오는 request 경로를 다른 destination 경로로 Redirect할 수 있습니다. Redirect을 사용하려면 next.config.js에서 redirects 키를 사용할 수 있습니다.
redirects은 source, destination 및 permanent 속성이 있는 객체를 포함하는 배열을 반환하는 비동기 함수입니다.
source: 들어오는 request 경로 패턴 (request 경로)
destination: 라우팅하려는 경로 (redirect할 경로)
permanent: true인 경우 클라이언트와 search 엔진에 redirect를 영구적으로 cache하도록 지시하는 308 status code를 사용하고, false인 경우 일시적이고 cache되지 않은 307 status code를 사용합니다.
https://nextjs.org/docs/api-reference/next.config.js/redirects
`/about/:path*` /// /about/185135/nice/dkf552
`/no/:path*`
Rewrites (URL변경되지 않음)
Rewrites를 사용하면 들어오는 request 경로를 다른 destination 경로에 매핑할 수 있습니다.
Rewrites은 URL 프록시 역할을 하고 destination 경로를 mask하여 사용자가 사이트에서 위치를 변경하지 않은 것처럼 보이게 합니다. 반대로 redirects은 새 페이지로 reroute되고 URL 변경 사항을 표시합니다.
https://nextjs.org/docs/api-reference/next.config.js/rewrites
주의! fetch할 때 /api/movies 또는 http://localhost:3000/api/movies 둘 다 가능하지만 http가 아닌 https로 fetch하게 되면 오류가 발생합니다.
네트워크 탭에서도 api key 드러나지않고 api/movie로 나타난다! \
.gitignore, 28 ~ 29 line 에
# local env files
.env*.local
라고 써져 있는 것 보니까 .env 파일을 만들때 .env 가 아닌 .env.local 라고 해야하나 봅니다. .env 파일을 만들으라고 next.js 팀이 .gitignore 파일에 넣어줬을 텐데 분명히...
생각해보니까, 그러면 .env 파일을 쓰라고 하면 .env 파일이 .gitignore 에 있을 텐데 없고, 다른 사람들이 이 프로젝트를 클론해서 같이 개발하려고 하면은 .env 파일을 클론을 못하고, .env 파일을 만들어서 뭔갈 할때도 거기다가 무슨 값을 집어넣어야 할지 모르니까 .env.example 파일을 만들어서 .env 파일의 모양을 사람들에게 알려줍시다! 그리고 .env 파일을 작성할때는 .env.local 로 만들고.
혹시 파라미터 관련해서 저같은 문제를 겪을 지도 모르는 분을 위해 댓글 남겨봅니다.
fetch를 할 때 파라미터를 여러 개 붙여서 요청한다면 이런 식일 겁니다.
fetch(`/api/foo=bar&key=val`)
그리고 config에서 rewrite를 이렇게 해주죠.
{
source: "/api/:params",
destination: `https://some.api/items?key=${API_KEY}&:params`
}
그런데 무슨 문제가 생기냐면, destination에서 "&:" 부분을 그대로 인식하지 않고 "&__ESC_COLON_" 이라는 문자열로 바꿔버립니다.
그렇기 때문에 destination을 다음과 같이 바꿔주어야 합니다.
`https://some.api/items?key=${API_KEY}${encodeURIComponent("&")}:params`
이렇게 하면 :params로 넘어온 문자열이 &와 문제없이 결합합니다.
다른 공공기관 API로 진행을 해봤는데, 주소에 한글이 들어가는 경우 주소 전체를 encodeURI()로 변경해주니까 되네요.
안되시는 분들은 참고하세요
- TypeError: Request path contains unescaped characters
- before : `https://openapi.gg.go.kr/RegionMnyFacltStus?KEY=${API_KEY}&Type=json&pIndex=1&pSize=20&SIGUN_NM=${SIGUN_NM}`
(SIGUN_NM : 지역 시/군 한글입력)
- after : encodeURI(
`https://openapi.gg.go.kr/RegionMnyFacltStus?KEY=${API_KEY}&Type=json&pIndex=1&pSize=20&SIGUN_NM=${SIGUN_NM}`
)
prerender ->초기 화면을 html으로 줌 모든 것이 로딩되었지만 소스코드에 loading..적혀있음
미리 렌더하는 방식,data와 동시에 렌더하는 방식 두 가지가있다.
모든 데이터 나온뒤 렌더하기
getServerSideProps export하기
index.js에 같이 있는 function Home은 potato이든 tomato이든 상관없지만
이건 이름 변경하면 안됨!!
해단 function 안에 코드는 모두 서버에서 작동함
->api키를 이곳에 작성하면 서버에서만 작동하기 때문에 클라이언트에 드러나지않음
object를 return 하고 prop라는 키가있다. 안에 원하는 데이터를 넣으면 됨
_app.js 실행 -> <component(index.tsx에 있는 Home component) {index.tsx에 있는 getSeverSideData 실행 후 function home 으로 prop 전달 후 실행 }/>
getServerSideProps
page에서 서버 측 랜더링 함수인 getServerSideProps함수를 export하는 경우 Next.js는 getServerSideProps에서 반환된 데이터를 사용하여 각 request에서 이 페이지를 pre-render합니다. getServerSideProps는 서버 측에서만 실행되며 브라우저에서는 실행되지 않습니다.
https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props
getServerSideProps를 사용하여 request시 데이터 fetch하기
다음 예는 request 시 데이터를 fetch하고 결과를 pre-render하는 방법을 보여줍니다.
(fetch할 때 오류 뜨시는 분들은 https를 http로 바꿔주시면 됩니다.)
```
export default function Home({ data }) {
// 데이터 랜더링
}
// 매 request마다 실행됩니다.
export async function getServerSideProps() {
const res = await fetch(`https://.../data`);
const data = await res.json();
// props를 통해 page에 data전달
return { props: { data } }
}
```
https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props#using-getserversideprops-to-fetch-data-at-request-time
getServerSideProps (타입스크립트와 함께 사용하기)
https://nextjs.org/docs/api-reference/data-fetching/get-server-side-props#getserversideprops-with-typescript
언제 getServerSideProps를 사용해야 하나요?
request time에 반드시 데이터를 fetch해와야 하는 페이지를 pre-render해야 하는 경우에만 getServerSideProps를 사용해야 합니다.
데이터를 pre-render할 필요가 없다면 client side에서 데이터를 가져오는 것을 고려해야 합니다.
클라이언트 측에서 데이터 가져오는 과정 (Fetching data on the client side)
페이지에 자주 업데이트되는 데이터가 포함되어 있고 데이터를 pre-render할 필요가 없는 경우 클라이언트 측에서 데이터를 가져올 수 있습니다.
1. 먼저 데이터가 없는 페이지를 즉시 표시합니다.
2. 페이지의 일부는 Static Generation을 사용해 pre-render할 수 있습니다.
3. 없는 데이터를 위해 loading 상태를 표시할 수 있습니다.
4. 그런 다음 클라이언트 측에서 데이터를 가져와 준비가 되면 표시합니다.
이 접근 방식은 예를 들어 사용자 대시보드 페이지에 적합합니다.
왜냐하면 대시보드는 사용자별 비공개 페이지이기 때문에 SEO와는 관련이 없으며 페이지를 미리 렌더링할 필요가 없습니다. 또한 데이터는 자주 업데이트되므로 요청 시 데이터를 가져와야 합니다.
getServerSideProps가 오류 페이지를 렌더링합니까?
getServerSideProps 내부에서 오류가 발생하면 pages/500.js 파일이 표시됩니다.
500 page(서버 렌더링 오류 페이지)는 사용자가 커스터 마이징 할 수 있습니다.
개발 중에는 이 파일이 사용되지 않고 대신 개발 오버레이가 표시됩니다.
서버사이드렌더링은
모든걸 받아오기 전까지 클라이언트가 아무것도 볼 수 없다는 단점.
html에 데이터가 구현되어있어서 서치엔진에는 좋다는 장점.
Dynamic Routes
url에 변수 넣기
pages>moive floder >[id].js 대괄호는 변수를 담는 이름
localhost:3000/about처럼 페이지 하나짜리는 굳이 폴더 만들 필요없고
pages >about.js로 충분!
create-react-app에서 변수는 /:id로 생성했다.
Next.js에서는 page에 대괄호[param]를 추가하여 Dynamic Route를 생성할 수 있습니다.
/movies/1, /movies/abc 등과 같은 모든 경로는 pages/movies/[id].js와 일치합니다.
```
const router = useRouter()
console.log(router);
const { id } = router.query
```
https://nextjs.org/docs/routing/dynamic-routes
Catch all routes
대괄호 안에 세 개의 점(...)을 추가하여 모든 경로를 포착하도록 Dynamic Routes를 확장할 수 있습니다. pages/movies/[...id].js는 /movies/1와 일치하지만 /movies/1/2, /movies/1/ab/cd 등과도 일치합니다. 일치하는 매개변수는 페이지에 쿼리 매개변수로 전송되며 항상 배열이므로 /movies/a 경로에는 다음 쿼리 개체가 있습니다.
ex) { "id": ["a"] }
https://nextjs.org/docs/routing/dynamic-routes#catch-all-routes