Next
React 官方网站给出了 Next
的推荐建议。 但是 Next
的野心不仅如此。 它和它的竞品 Gatsby
和 Remix
在目的上有高度的重叠,在实现上有不同的 哲学
提示
If you’re building a server-rendered website with Node.js, try Next.js.
如果你要做 SSR (服务端渲染)你可以试试 Next
Dev Env Setup
- create-next-app
Navigation
HTML A Tag
- Reload Page
Link Component
- Not Reload
import Link from "next/link";
Dynamic Page
useRouter hook
import { useRouter } from "next/router"; // ... FC const router = useRouter(); const { sameAsFileName } = router.query;
Static Files
- public folder
Image Component
Key Feature with Performance Optimization
- local image
- remote image
- config is necessary
Head Component
same as Helmet component in other framework like
Gatsby
Head
import Head from "next/head";
- avoid duplication
- key
- avoid duplication
App Component
_app.tsx
similar with index.tsx in other framework
import type { AppProps } from "next/app";
export default function App({ Component, pageProps }: AppProps) {
return (
<div>
{/* The Component is Page Component */}
<Component {...pageProps} />
</div>
);
}
Document Component
_document.tsx
- running in server side
import Document, { Html, Head, Main, NextScript } from "next/document";
class MyDocument extends Document {
render() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
export default MyDocument;
CSS
App Level
- add css into
_app.tsx
Component Level
css module
- common css grammar
- use as object literal
Inline Level
css in js
<div style={{ display: "flex", flexDirection: "row", rowGap: "24px", justifyContent: "space-between", alignItems: "center", }} > <Button /> </div>
Layout
App Level
- common layout component
- injected into
_app.tsx
- injected into
Page Level
getLayout
method
this is not official way
import type { ReactNode } from "react";
import { Heading } from "@chakra-ui/react";
import Layout from "../src/components/layout";
const Home = () => {
return (
<Heading w="full" textAlign="center">
This is our homepage content!
</Heading>
);
};
Home.getLayout = (page: ReactNode) => {
return <Layout>{page}</Layout>;
};
export default Home;
getLayout
method invoked in_app.tsx
import type { ReactNode } from "react";
import type { AppProps } from "next/app";
import type { NextPage } from "next";
// import the custom layout
import Layout from "../src/components/layout";
type NextPageWithLayout = NextPage & {
getLayout?: (page: ReactNode) => ReactNode;
};
type AppPropsWithLayout = AppProps & {
Component: NextPageWithLayout;
};
const App = ({ Component, pageProps }: AppPropsWithLayout) => {
// ✍️ wrap the Component with the custom layout
const getLayout = Component.getLayout ?? ((page) => page);
return (
{getLayout(<Component {...pageProps} />)}
);
};
export default App;
SSG vs ISR vs SSR
提示
- SSG: Static Site Generation
- SSR: Server Side Rendering
- ISG: Incremental Static Regeneration
注意
- Rendering 是指 HTML 标签 的创建过程
SSG
- CI/CD machine build and deploy the static site bundle to server/cdn
- Website is pre-built
- Data is static too unless rebuild from CI/CD machine
SSR
- Website is built at runtime
- Query data from DB
- Generate HTML on the fly
- Pre-Built is opt
- Cache
- Server provide not only static assets but dynamic content
ISR
- Partially SSG
- Partially SSR
- Versioning
- Periodically
Comparison
数据
更新的频率
类型 服务器 浏览器 编译时 运行时 SPA Data SSG Data SSR Data ISG Data ⏰ 🔄
HTML
是在什么地方
什么时间渲染的
类型 服务器 浏览器 编译时 运行时 SPA HTML SSG HTML SSR HTML ISG HTML ⏰ 🔄
SSG
GetStaticProps
invoked at server side
import type { GetStaticProps } from "next";
type Props = {
foo: string[];
};
const Home = ({ foo }: Props) => {
return (
<List>
{foo.map((f) => (
<span>{foo}</span>
))}
</List>
);
};
export const getStaticProps: GetStaticProps<Props> = async (context) => {
return {
props: {
foo: ["a", "b", "c"],
},
};
};
export default Home;
GetStaticPaths
generate static page @build time
ISR
GetStaticProps
- revalidate
SSR
getServerSideProps
generate static page @runtime on every request
- vs
GetStaticProps
- context
- query
- req
- header
- cookie
- auth
- res
- context