Skip to content

Instantly share code, notes, and snippets.

@nurmdrafi
Last active January 20, 2023 06:19
Show Gist options
  • Save nurmdrafi/d31e0d237d526070c3573b7c74a4fc03 to your computer and use it in GitHub Desktop.
Save nurmdrafi/d31e0d237d526070c3573b7c74a4fc03 to your computer and use it in GitHub Desktop.
Next.js v13

Benefits

[*] Good for SEO
[*] Super Fast
[*] Future of React

Diff

[*] Next.js provides Server Side Rendering (S.S.R)
[*] React only provides Client Side Rendering

_app vs _document

[*] _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

Create Next.js Application

[*] npx create-next-app <app name>

Run Localhost Server

[*] npm run dev

Styles

[*] Home.module.css
[*] dont use hyphen(-) inside css variable
[*] import styles from "../styles/Home.module.css"
[*] use: className={styles.container}

Link

[*] 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>

Routes

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
	}
}

}

Head

[*] 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

getStaticProps function

[*] 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]

		}

Layout

_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)) }

getServerSideProps

export const getServerSideProps = async () => { const res = await axios.get(url) const data = res.data

return {
	props: {
		data // [*] this is actually props of this components
	}
}

}

getStaticPaths = async () => {

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
}

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment