본문 바로가기

코딩

트위터 클론코딩: 3 getServerSideProps(context),404page

728x90

Link로 navigate 하는 법 

import Link from "next/link"

<Link href={`/movies/${moive.id}`}>

 

 

RouterHook으로 Navigate 하는 법

ex) 유저가 form을 제출하면 클릭하지않아도 자동으로 navigate.

  const router = useRouter();
    const onClick = (id, title) => {
        router.push(`/movies/${title}/${id}`);
    };
    return (
        <div className="container">
            {results?.map((movie) => (
                <div
                    className="movie"
                    onClick={() => onClick(movie.id, movie.original_title)}
                    key={movie.id}
                >

 

 

nextconfig.js에 

영화를 가져오는 url에 apikey 보여주고싶지 않아서 rewrite

const nextConfig = {
    async rewrites() {
        return [

{
                source: "/api/movies/:id", //변수 이름 같아야함
                destination: `https://api.themoviedb.org/3/movie/:id?api_key=${API_KEY}`,
            },

 

 json받아오는지 localhost:3000//api/movies/ 영화아이디 url 방문하여 체크

 

 

url에서 url로 데이터 넘겨주는 법, 유저로부터 숨기는 법 

router.push(url, as, options)

url에 정보를 숨겨 보낼 수 있다.

 home에 이미 있는 데이터를 보냄 로드 할 때가지 기다리지 않아도 됨 

 

const onClick = (id) => {

            router.push({

            pathname: `/movies/${id}`,

            query:{

                  title:movie.original_title   //url에서 query?title=이런식으로 보임 router.push의 두번째 속성인 as로 mask

                      }

            },

`/moives/${id}` //속성 as 주소창에 이렇게 보임 

)

 

 

Detail.js 

const router = userRotuer();

return <h4>{router.query.title || "Loading.."}</h4>

 

위와 같은 로직은 home에서 상세페이지 클릭했을 때만 나타남 

바로 상세페이지 주소이동하거나 시크릿모드로 들어오면 영원히 "Loading..."

<Link >에서도 동일하게 적용하여 데이터 보낼 수 있다. <Link href={{pathname:`` query:{}},`/mvoies..`}>

 

 

router.push(url, as, options)
클라이언트 측 전환을 처리합니다. 이 방법은 next/link가 충분하지 않은 경우에 유용합니다.
url: UrlObject | String: 탐색할 URL
as: UrlObject | String: 브라우저 URL 표시줄에 표시될 경로에 대한 선택적 데코레이터입니다.
```
router.push({
pathname: '/post/[pid]',
query: { pid: post.id },
})
```
+ 외부 URL에 대해서는 router.push()를 사용할 필요가 없습니다.
window.location을 사용하는 것이 더 적합합니다.
https://nextjs.org/docs/api-reference/next/router#routerpush

Movie Detail API
API: https://api.themoviedb.org/3/movie/{movie_id}?api_key=api_key&language=en-US
https://developers.themoviedb.org/3/movies/get-movie-details

 

API Docs

 

developers.themoviedb.org

 

HTML5부터 a태그에 div 및 flow content를 넣어도 문제 없다고 하네요 !
http://html5doctor.com/block-level-links-in-html-5/

 

“Block-level” links in HTML5 | HTML5 Doctor

One new and exciting thing you can do in HTML 5 is wrap links round “block-level” elements. Imagine you have a front page with lots of teasers for news articles, each of which leads to a page devoted to the full text of that article. Obviously, each st

html5doctor.com

 

 

catch-all URL

[...id]

 

 

 

movie > [id].js  // string형태의 한개의 쿼리를 가져옴query 

[...id]  //배열로 모든 query를 받음 

const rotuer=useRouter()

console.log(router)//확인가능 

 

 

url에서 영화제목을 가져올 것이기 때문에 home->detail으로 이동한게 아니여도 됨!


export default function Home({ results }) {
    const router = useRouter();
    const onClick = (id, title) => {
        router.push(`/movies/${title}/${id}`);
    };
    return (
        <div className="container">
            {results?.map((movie) => (
                <div
                    className="movie"
                    onClick={() => onClick(movie.id, movie.original_title)}
                    key={movie.id}
                >
                    <img
                        src={`https://image.tmdb.org/t/p/w500/${movie.poster_path}`}
                    />
                    <Link href={`movies/${movie.original_title}/${movie.id}`}>

 

movie / [...params].js

 

export default function Detail() {
    const router = useRouter();
    const [title, id] = router.query.params || [];
    console.log(title, id);
    return <h1>{title}</h1>;
}

시크릿모드로 동작하면 에러발생

 

router는 클라이언트 단에서 실행하는데 Next.JS 같은 SSR 서버에서 (pre)렌더링 하는 경우엔
router가 실행이 되기 전이기 때문에 router 값이 없어서 오류가 뜬다.

 

 

혹시나 저처럼 왜 || [] 를 추가해주면 되는건지 궁금하신분들을 위해 남겨봅니다.
기본적으로 미리 렌더링이 되기때문에 먼저 html 파일이 내려온다는건 다들 아실겁니다. 이때 문제가 아직 js들이 다운로드가 안됐기 때문에 useRouter()로 정보를 제대로 가져오질 못하는 상태입니다. 그렇기 때문에 초기에는 빈 배열을 추가해줘서 오류가 발생하지 않도록 해주고, js가 내려가서 다시 렌더링하게되면 그 때는 빈 배열이 아닌 router.query.params에서 값을 가져와서 뿌려주는거죠.
정확하게 보고싶으신 분들은 검사 -> 네트워크 -> slow 3g 로 설정하신 후에 페이지 렌더링 확인하시면 먼저 html쪽 뜨고나서 js까지 모두 다운로드 된 후에야 title이 보이는걸 볼 수 있으실거예요.추가로 위와 같은 이유로 console.log(router)를 찍으면 2번 보이는겁니다.

 

 

client로 렌더링한것이여서 소스코드 확인하면 제목이 어디에도 없을꺼임 그냥<script>

 

 

 

 

server에서  렌더링하기 

export function getServerSideProps(ctx) { //export 꼭하기! 안 해서 결과 안나왔었음..
    console.log(ctx);
    return {
        props: {},
    };
}

context 전달해줌

console.log(context)

 

import Seo from "@/components/Seo";
import { useRouter } from "next/router";

export default function Detail({ params }) {
    const router = useRouter();
    const [title, id] = params || [];

    return (
        <>
            <Seo title={title} />
            <h1>{title}</h1>
        </>
    );
}

export function getServerSideProps({ params: { params } }) {
    return {
        props: { params

         },
    };
}

 

기본적으로 pre-render 해서

유저에게 로딩하는걸 절대 보여주고싶지않고

seo검색에 최적화하고싶다면(소스코드에 나옴)

또는  유저가 접속하기 전에 탭이름을 바꾸고  싶을 때 getServerSideProps사용

getServerSideProps으로

fetch하는 것 뿐만이아니라 단순히 영화제목과 id를 좀더 데이터를 빠르게  얻기우해 사용 할 수 잇음

 

getServerSideProps
페이지에서 getServerSideProps(서버 측 렌더링)라는 함수를 export하는 경우 Next.js는 getServerSideProps에서 반환된 데이터를 사용하여 각 request에서 이 페이지를 pre-render합니다.
https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props

getServerSideProps (Context parameter)
params: 이 페이지에서 dynamic route(동적 경로)를 사용하는 경우 params에 route parameter가 포함됩니다. 페이지 이름이 [id].js이면 params는 { id: ... }처럼 보일 것입니다.
query: 쿼리 문자열을 나타내는 객체입니다.
https://nextjs.org/docs/api-reference/data-fetching/get-server-side-props#context-parameter

getServerSideProps (타입스크립트와 함께 사용하기)
```
import { GetServerSideProps } from 'next'

export const getServerSideProps: GetServerSideProps = async (context) => {
// ...
}

function Page({ data }: InferGetServerSidePropsType< typeof getServerSideProps>)
```
https://nextjs.org/docs/api-reference/data-fetching/get-server-side-props#getserversideprops-with-typescript

router.query.params 타입 지정 (타입스크립트)
```
type MovieDetailParams = [string, string] | [];

const router: NextRouter = useRouter();
const [title, id] = (router.query.params || []) as MovieDetailParams;

 


```

https://stackoverflow.com/questions/69058259/how-to-access-route-parameter-inside-getserversideprops-in-next-js

 

How to access route parameter inside getServerSideProps in Next.js?

I want to query my Supabase table using the ID in the slug e.g. localhost:3000/book/1 then show information about that book on the page in Next.js. Table book/[id].js import { useRouter } from 'next/

stackoverflow.com

As described in getServerSideProps documentation, you can access the route parameters through the getServerSideProps's context, using the params field.

params: If this page uses a dynamic route, params contains the route parameters. If the page name is [id].js, then params will look like { id: ... }.

export async function getServerSideProps(context) {
    const id = context.params.id // Get ID from slug `/book/1`
    
    // Rest of `getServerSideProps` code
}

Alternatively, you can also use the query field to access the route parameters. The difference is that query will also contain any query parameter passed in the URL.

export async function getServerSideProps(context) {
    const id = context.query.id // Get ID from slug `/book/1`
    // If routing to `/book/1?name=some-book`
    console.log(context.query) // Outputs: `{ id: '1', name: 'some-book' }`

    // ...
}

As described in getServerSideProps documentation, you can access the route parameters through the getServerSideProps's context, using the params field.

params: If this page uses a dynamic route, params contains the route parameters. If the page name is [id].js, then params will look like { id: ... }.

export async function getServerSideProps(context) {
    const id = context.params.id // Get ID from slug `/book/1`
    
    // Rest of `getServerSideProps` code
}
Alternatively, you can also use the query field to access the route parameters. The difference is that query will also contain any query parameter passed in the URL.

export async function getServerSideProps(context) {
    const id = context.query.id // Get ID from slug `/book/1`
    // If routing to `/book/1?name=some-book`
    console.log(context.query) // Outputs: `{ id: '1', name: 'some-book' }`

    // ...
}

 

404page만들기 

최상단에 404.js만들어서

export default function notFound() {
    return (
        <div>
            <h1>WHat r u doing here?</h1>
        </div>
    );
}작성함

아무경로로 이동하면 위와같이 적용됨