Single Shared Layout with Custom App
만약 내가 전체의 애플리케이션에서 하나의 레이아웃만을 가지고 있다면 나는 Custom App을 생성할 수 있다. 그리고 이 Custom App으로 나의 애플리케이션 레이아웃을 감싸면 된다.
또한 만약 내가 많은 레이아웃을 사용하고 싶다면 내 페이지에 있는 getLayout 속성을 추가해서 사용하면 된다.
// pages/index.js
import AppLayout from "../components/AppLayout";
import styles from "../styles/Home.module.css";
export default function Home() {
return <div className={styles.container}></div>;
}
Home.getLayout = (page) => {
return <AppLayout>{page}</AppLayout>;
};
// pages/_app.js
import "../styles/globals.css";
import "../scss-styles/global.scss";
import variables from "../scss-styles/variables.module.scss";
import AppLayout from "../components/AppLayout";
function MyApp({ Component, pageProps }) {
const getLayout = Component.getLayout || ((page) => page);
return (
<AppLayout color={variables.primaryColor}>
<Component {...pageProps} />
</AppLayout>
);
}
export default MyApp;
이러한 패턴은 우리에게 state persistence를 제공한다 왜냐하면 React Component트리가 페이지가 바뀌어도 유지되기 때문이다. Component 트리를 통해 React는 어떠한 Element가 바뀌어야 할지 아니면 보존되어야 할 지 알기 때문입니다.
with TypeScript
// components/Layout.tsx
import React from "react";
import styles from "../scss-styles/Layout.module.scss";
import type { NextPage } from "next";
type LayoutPage = NextPage;
const Layout: LayoutPage = ({ children }) => {
return <div className={styles.divLayout}>{children}</div>;
};
export default Layout;
// pages/index.tsx
import Layout from "../components/Layout";
import type { ReactElement } from "react";
import type { NextPageWithLayout } from "./_app";
import styles from "../scss-styles/IndexPage.module.scss";
const Home: NextPageWithLayout = () => {
return <div className={styles.indexContainer}>Home page</div>;
};
Home.getLayout = (page: ReactElement) => {
return <Layout>{page}</Layout>;
};
export default Home;
// pages/_app.js
import "../styles/globals.css";
import type { NextPage } from "next";
import type { AppProps } from "next/app";
import type { ReactElement, ReactNode } from "react";
export type NextPageWithLayout = NextPage & {
getLayout?: (page: ReactElement) => ReactNode;
};
type AppPropsWithLayout = AppProps & {
Component: NextPageWithLayout;
};
function MyApp({ Component, pageProps }: AppPropsWithLayout) {
const getLayout = Component.getLayout || ((page) => page);
return getLayout(<Component {...pageProps} />);
}
export default MyApp;
// scss-styles/Layout.module.scss
.divLayout {
background-color: bisque;
height: 200px;
width: 200px;
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
Data Fetching
만약 Layout안에서 데이터를 가져오고 싶다면 우리는 client-side에서 useEffect나 SWR라이브러리를 이용하여 페이지 안으로 가져와야 한다. 그 이유는 Layout은 Page가 아니기 때문에 getStaticProps나 getServerSideProps를 사용할 수 없기 때문이다.
// component/Layout.tsx
import React, { useEffect, useState } from "react";
import styles from "../scss-styles/Layout.module.scss";
import type { NextPage } from "next";
import axios from "axios";
type LayoutPage = NextPage;
type user = {
id: number;
name: string;
username: string;
email: string;
address: any;
};
type users = user[] | undefined;
type layOutFetchUserProps = {
usersData: users;
};
const LayOutFetchUser = ({ usersData }: layOutFetchUserProps) => {
if (usersData) {
return (
<ul className={styles.userWrapper}>
{usersData.map((user) => {
return <li key={user.id}>{user.name}</li>;
})}
</ul>
);
} else {
return <div>Laoding..</div>;
}
};
const Layout: LayoutPage = ({ children }) => {
const [users, setUsers] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await axios.get(
`https://jsonplaceholder.typicode.com/users`
);
setUsers(response.data);
} catch (error) {
console.error(error);
}
};
fetchData();
}, []);
return (
<div className={styles.divLayout}>
{children}
{!users ? <div>Loading Users ...</div> : <LayOutFetchUser usersData={users} />}
</div>
);
};
export default Layout;
// pages/index.tsx
import Layout from "../components/Layout";
import type { ReactElement } from "react";
import type { NextPageWithLayout } from "./_app";
import styles from "../scss-styles/IndexPage.module.scss";
const Home: NextPageWithLayout = () => {
return <div className={styles.indexContainer}>Home page</div>;
};
Home.getLayout = (page: ReactElement) => {
return <Layout>{page}</Layout>;
};
export default Home;
// scss-styles/Layout.nmodule.scss
.divLayout {
background-color: bisque;
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.userWrapper {
list-style: none;
& > li {
margin: 10px 2px;
text-align: center;
padding: 0;
}
}
page에서 data-fetching을 하고 싶으면 getStaticProps나 getServerSideProps를 사용하면 된당~
'Web > NextJs' 카테고리의 다른 글
Next.js - Image Optimization (0) | 2022.02.25 |
---|---|
Next.js - useSWR (0) | 2022.02.25 |
Next.js - Built-in CSS Support (0) | 2022.02.23 |
Next.js - Data Fetching ( getStaticProps, getStaticPaths ) (0) | 2022.02.18 |
Next.js - Data Fetching ( getServerSideProps ) (0) | 2022.02.18 |