[Nomad-coders] NextJS 시작하기 #2

김시아·2022년 7월 6일
0

2.0 Patterns

보통 사람들은 _app.js파일에 내용이 많은 것을 안좋아하므로
Layout.js컴포넌트에 _app.js를 넣어 커스텀한다.

Layout.js

export default function Layout({ children }) {
  return (
    <>
      <div>{children}</div>
    </>
  );
}

_app.js

export default function App({ Component, pageProps }) {
  return (
    <Layout>
      <Component {...pageProps} />  <!--Layout의 children-->
    </Layout>
  );
}

head component

import Head from "next/head";

export default function Home() {
  return (
    <div>
      <Head>
        <title>title</title>  <!--html head의 title-->
      </Head>
      ~~~
    </div>
  );
}

2.1 Fetching Data

image

public 폴더에 넣기
<img src="/xxx.png" />
<!-- Next는 img 태그 말고 Image component(next 내장)를 쓰라고 권장한다 -->

API

const API_KEY = "~~";

export default function AAA() {
  const [aaa, setAaa] = useState();
  useEffect(() => {
    (async () => {
      const { results } = await ( //objects에 results key가 있을 때 바로 받을 수 있음
        await fetch(`URL/${API_KEY}`)
      ).json();
      setAaa(results);
    })();
  }, []);
  
  return (
    <div>
      {!aaa && <h3>Loading...</h3>}
      {aaa?.map((a) => (
        <div key={a.id}>
          <span>{a.~~}</span>
        </div>
        ))}
    </div>
    );
}

2.2 Redirect and Rewrite

redirect

next.config.js 수정하기

  ...
  // contact 페이지에 가면 form 페이지로 리다이렉트 됨
  async redirects() {
    return [
      {
        source: "/contact",
        destination: "/form",
        permanent: false,
      },
    ];
  },
};
  //위의 방법은 패턴 매칭도 가능하다
	return [
      {
        source: "/contact/:path*",  //*을 붙이면 모든 걸 catch
        destination: "/form/:path*",
        permanent: false,
      },
      {
        source: ~~~ //redirect를 추가하고 싶을 때 
      }
    ];

rewrite

: 유저를 redirect 시키기는 하지만 url이 변하지 않음
-> API를 호출할 때 유저가 API key를 볼 수 없음

  ...
  async redirects() { ...
  },
  async rewrites() {
    return [
      {
        source: "/api/~~",
        destination: `URL${API_KEY}`
      },
    ];
  },
};

위의 작성 내용을 활용하면

  useEffect(() => {
    (async () => {
      const { results } = await ( //objects에 results key가 있을 때 바로 받을 수 있음
        await fetch("/api/~~")
      ).json();
      setAaa(results);
    })();
  }, []);

API KEY .env 파일로 옮기기

const API_KEY = process.env.API_KEY;

//.env 파일 생성 및 꼭 gitignore 에 넣기
API_KEY = ~~~

2.3 Server Side Rendering

get server side props

: 서버 쪽에서만 실행되는 코드
: 유저가 볼 수 없기 때문에 여기서 API를 호출해도 좋다
: 데이터를 다 준비한 후에 페이지 렌더링
-> 자바스크립트를 비활성화해도 페이지를 띄울수있다는 장점과 데이터를 받기 전까지는 빈 화면인 단점

export async function getServerSideProps() { // 함수 이름 바꾸면 안됨
  const { results } = await (await fetch(`URL/${API_KEY}`)).json();
  return {
    props: {
      results,
    },
  };
}

위의 results를 받아오려면

export default function AAA({results}) { ...
}

2.5 Dynamic Routes

nested router (중첩 라우터)

  1. url을 movies/all 로 만들고 싶을 때
  • pages 폴더에 movies 폴더를 만들고 all.js 파일 만들어주기
  1. movies/all url을 사용중인데 movies 라는 url도 사용하고 싶다면
  • movies 폴더에 index.js 파일 만들어 사용하기

페이지가 하나뿐이라면 폴더를 만들 필요는 없음

dynamic URL

  1. url을 movies/영화별 고유번호(변수) 로 만들고 싶을 때
  • movies 폴더에 [id].js 파일 만들기 //id는 변수
import { useRouter} from "next/router";

export default function BBB() {
  const router = useRouter();  //router의 query에 id 정보가 들어있음
  ...
}

2.6 Movie Detail

이전에 다른 페이지로 가기 위해 Link 컴포넌트를 사용했었는데
Link는 <Link><a></a></Link> 구조이고, a 태그 안에 클릭할 요소들이 들어가야 한다.
보편적으로 a 태그 안에는 텍스트를 넣는데, 텍스트 하나가 아닌 div 태그를 넣어야 하는 경우에는?
useRouter 훅을 사용할 수 있다. (a 태그 안에 div를 넣는다고 동작이 안되는건 아님)

const router = useRouter();
const onClick = (id) => {
  router.push(`~~/${id}`);
};
...
<div onClick={() => onClick(id)} ... />
...

(리액트로 웹사이트를 만들 때 나도 위의 두 가지 방법을 혼용했었는데 사실 태그안에 뭐가 들어가야한다? 이거보다는 단순 클릭에 의한 페이지 이동(Link)과 조건에 의한 페이지 이동(router)으로 구분지어 사용하곤 했었다)

router로 object 보내기

//예시 1
//url에 ~~~/id?title=potato 라고 표시 된다
const onClick = (id) => {
  router.push({
  	pathname: `~~/${id}`,
    query: {
      title: "potato", 
    },
  });
};

//예시 2
//위의 query 부분을 url에서 숨길 수 있다
const onClick = (id) => {
  router.push({
  	pathname: `~~/${id}`,
    query: {
      title: "potato",
    },
  }, `~~/${id}`);
};

데이터 받을 때는 router의 query에 다 들어있다

Link로 object 보내기

:as는 url을 마스킹

<Link 
  href={{
    pathname: `~~/${id}`,
    query: {
      title: "potato",
    }
  }}
  as={`~~/${id}`}
  >
</Link>

2.7 Catch All

  • 기존에 [id].js 파일이름 앞에 ...추가 해주기 (ex. [...params.js])
    -> id 앞에 다른 내용이 와도 기존에 의도하던 페이지 렌더링 가능
    -> 이 경우 route 쿼리에 params가 배열로 옴 (슬래시로 나눠져서 배열로 들어감)

~~/title/id로 url을 만드는 경우

export default function BBB() {
 const router = useRouter();
 const [title, id] = router.query.params || [];
 //빈 배열을 넣어주는 이유는 Url로 바로 접근했을 때 예외를 처리하기 위함
 ...
}

url로 바로 접근하여 title을 뿌리는 경우,
client-side 렌더링이므로 html 코드에 내용이 없음 -> seo가 알 수 없음

export default function BBB({ params }) {
  const router = useRouter();
  const [title, id] = params || [];
  ...
}
  
export function getServerSideProps({ params: { params } }) {
  return {
    props: {
    	params,
    },
  };
}

2.8 404 Pages

: pages 폴더에 404.js 파일 만들기

0개의 댓글