보통 사람들은 _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>
);
}
import Head from "next/head";
export default function Home() {
return (
<div>
<Head>
<title>title</title> <!--html head의 title-->
</Head>
~~~
</div>
);
}
public 폴더에 넣기
<img src="/xxx.png" />
<!-- Next는 img 태그 말고 Image component(next 내장)를 쓰라고 권장한다 -->
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>
);
}
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를 추가하고 싶을 때
}
];
: 유저를 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 = ~~~
: 서버 쪽에서만 실행되는 코드
: 유저가 볼 수 없기 때문에 여기서 API를 호출해도 좋다
: 데이터를 다 준비한 후에 페이지 렌더링
-> 자바스크립트를 비활성화해도 페이지를 띄울수있다는 장점과 데이터를 받기 전까지는 빈 화면인 단점
export async function getServerSideProps() { // 함수 이름 바꾸면 안됨
const { results } = await (await fetch(`URL/${API_KEY}`)).json();
return {
props: {
results,
},
};
}
위의 results를 받아오려면
export default function AAA({results}) { ...
}
페이지가 하나뿐이라면 폴더를 만들 필요는 없음
import { useRouter} from "next/router";
export default function BBB() {
const router = useRouter(); //router의 query에 id 정보가 들어있음
...
}
이전에 다른 페이지로 가기 위해 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)으로 구분지어 사용하곤 했었다)
//예시 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에 다 들어있다
:as
는 url을 마스킹
<Link
href={{
pathname: `~~/${id}`,
query: {
title: "potato",
}
}}
as={`~~/${id}`}
>
</Link>
~~/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,
},
};
}
: pages 폴더에 404.js
파일 만들기