[*] Good for SEO
[*] Super Fast
[*] Future of React
[*] Next.js provides Server Side Rendering (S.S.R)
[*] React only provides Client Side Rendering
[*] _app
[*] Next.js uses the App component to initialize pages.
[*] Persisting layout between page changes
[*] Keeping state when navigating pages
[*] Custom error handling using componentDidCatch
[*] Inject additional data into pages
[*] Add global CSS
[*] _document
[*] This file is used to set language, load fonts, load scripts before page interactivity, collect style sheets for CSS in JS solutions like Styled Components
[*] this file only rendered in server
[*] We can have both _app & _document file, they overlap slightly in terms of functions, but they do not necessarily conflict with each other.
[link] https://github.com/vercel/next.js/discussions/39821
[*] npx create-next-app <app name>
[*] npm run dev
[*] Home.module.css
[*] dont use hyphen(-) inside css variable
[*] import styles from "../styles/Home.module.css"
[*] use: className={styles.container}
[*] import Link from "next/link"
[*] <Link href="/about">Go To About</Link>
[x] initially link dont have styles
<Link href="/about">
<a className='nav-link'>About</a>
</Link>
[x] <Link href="/news/[id]" as = {`/news/${news.id}`}>
<a className='nav-link'>Read More</a>
</Link>
pages > profile > [id].js
import { userRouter } from "next/router"
const Profile = () => {
const router = useRouter()
const {id} router.query
return <div>Hello {id}</div>
}
[*] 404.js NotFound
[*] Different way without useRouter
[*] By default getStaticProps & getServerSideProps both has (context) parameter
[*] [id].js (dynamic routes and fetch data)
export const getServerSideProps = async (context) => {
const res = await axios.get(`url` + context.params.id)
const data = res.data
return {
props: {
data
}
}
}
[*] import Head from "next/head"
[*] used for meta tag
[*] title
[*] dynamic head
[*] components > Meta.js
import Head from 'next/head'
const Meta = ({title, keywords, description}) => {
return (
<Head>
<title>{title}</title>
<meta charset='utf-8 />
<meta httpEquiv='X-UA-Compatible' content='IE=edge'/>
<meta name='viewport' content='width=device-width, initial-scale=1' />
<meta name='keywords' content={keywords} />
</Head>
)
}
Meta.defaultProps = {
title: "title...",
keywords: "keywords...",
description: "description..."
}
export default Meta
[*] used for fetch data from external API
[*] getStaticProps pre-render page at build time, known as SSG
[*] another function is getServerSideProps
[*] both of them has their own usecase
> getServerSideProps is really usefull when we have to render page at request time
> like our order table data is frequently variable
> getStaticProps used when data is static
[*] write end of component
[*] we dont need useEffect hook for fetch data on initial load
/// Example
const CoinList = ({coinData}) => {
return (
<div>
{coinData.coins.map((coin) => {
return <h2>{coin.name}<h2>
})}
</div>
)
}
export const getStaticProps = async () => {
const res = await axios.get(url);
return {
props: {
coinData: res.data
}
}
}
[*] what if we need to fetch data by query params
// example
export const getStaticProps = async ({params}) => {
const id = params.id
const res = await axios.get(url);
return {
props: {
coinData: res.data
},
revalidate: 10, [regenerate data after 10m sec]
}
_app.tsx
import type { AppProps } from 'next/app'
import { useRouter } from 'next/router'
import { Provider } from 'react-redux'
import store from '../redux/store'
// Import Components
import MenuLayout from '../components/MenuLayout'
// Import Styles
import '../styles/globals.css'
const App = ({ Component, pageProps }: AppProps) => {
// States
const router = useRouter()
return (
<Provider store={ store }>
<div style={containerStyles}>
{ (router?.asPath === '/login' router?.asPath === '/signup' || router?.asPath === '/') ?
(
<Component { ...pageProps } />
)
:
(
<MenuLayout>
<Component { ...pageProps } />
</MenuLayout>
)
}
</div>
</Provider>
)
}
// Styles
const containerStyles = {
boxSizing: 'border-box' as 'border-box',
width: '100%',
height: '100vh',
overflow: 'hidden'
}
export default App
MenuLayout.jsx
import React, { useState } from 'react';
// Import Components
import { Layout } from 'antd';
import LeftNav from './LeftNav/LeftNav'
import TopNav from './TopNav/TopNav'
// Import Methods
import { useAppSelector } from '../redux/store';
import Dashboard from '../pages/dashboard'
// Import Constants
const { Header, Sider, Content } = Layout
const MenuLayout = ({ children }) => {
console.log(children, "children")
// Get Data from Redux
const isLeftNavOpen = useAppSelector(state => state?.nav?.isLeftNavOpen ?? true)
const leftNavWidth = useAppSelector(state => state?.nav?.leftNavWidth ?? 240)
return (
<div style={ containerStyles }>
<Layout>
<Header style={{width: "100%"}}>
<TopNav/>
</Header>
<Layout hasSider={true}>
<Sider
className='left-nav-container'
theme='light'
trigger={ null }
collapsed={ !isLeftNavOpen }
collapsedWidth={ 100 }
collapsible={ true }
width={ leftNavWidth }
>
<LeftNav/>
</Sider>
<Content>{ children }</Content>
</Layout>
</Layout>
</div>
);
};
// Styles
const containerStyles = {
width: '100%',
height: '100%',
overflow: 'hidden'
}
export default MenuLayout;
[*] another serverside rendering without reload const refreshData = () => { router.replace(router.asPath, undefined, (scroll: false)) }
export const getServerSideProps = async () => { const res = await axios.get(url) const data = res.data
return {
props: {
data // [*] this is actually props of this components
}
}
}
const res = await axios.get(url)
const data = res.data
const ids = data.map(d => d.id)
const paths = ids.map(id => ({params: {id: id.toString()}}))
return {
paths: [{params : {id: '1'}}] // comment out
paths
fallback: false
}
}