Terakhir diperbaharui: Jan 21, 2021
Next.js
Daftar Isi
Apa itu Next.js? Features Step by step - Persiapan - Install Next JS - Navigation - Membuat halaman baru - Link antar halaman - Layout Components - Styles - Global Styles - Asset - Pre-rendering - Data Fetching - Dynamic Routes/ URLs - Deployment LainnyaApa itu Next.js?
Next.js adalah framework React yang dibuat untuk mengatasi masalah client-side rendering yang dimiliki React.
Sebuah halaman website yang dibuat menggunakan React ‘terasa ringan’ karena tampilan website sangat interaktif.
Selain itu, saat data berubah, React dengan efisien akan mengupdate bagian dari halaman website yang memang perlu diupdate tanpa perlu reload satu halaman penuh.
Untuk mendapatkan itu semua, client harus load semua file JavaScript sebelum konten halaman ditampilkan. Jika file JS cukup besar maka waktu yang dibutuhkan untuk load pertama kali juga menjadi lebih lama.
Masalah lain dari client-side rendering adalah SEO, ada kemungkinan web crawler berusaha mengindex halaman yang belum selesai dirender sepenuhnya (karena waktu load yang lama). Dan menganggap web tersebut blank.
Kedua masalah di atas dapat diselesaikan dengan teknik pre-rendering. Yaitu halaman HTML dan file JavaScript di generate sebelum dikirim ke client.
Ada 2 bentuk pre-rendering yaitu Server Side Rendering (SSR) dan Static Site Generator (SSG).
Server Side Rendering(SSR)
Sesuai namanya proses render terjadi di server dan bukan di client, setiap request ke server akan direspon dengan sebuah halaman HTML.
Static Site Generator (SSG)
Setiap request ke server akan direspon dengan halaman HTML yang sudah selesai digenerate pada saat proses build. Teknik cache menggunakan CDN dapat diterapkan untuk mempersingkat waktu akses.
Dan Next.js dapat melakukan keduanya.
Features
Selain pre-rendering, Next.js juga memiliki beberapa fitur untuk memudahkan kita dalam membuat aplikasi React:
- Page-based routing system, alamat dari halaman adalah nama file dari halaman tersebut
- Code splitting, code JavaScript dipecah menjadi chunk agar waktu loading halaman menjadi lebih singkat
- Client-side routing, routing juga bisa dilakukan di sisi client
- Fast refresh support, mirip dengan hot reloading
- Built-In CSS, support CSS Module, SAAS dan CSS-in-JS
- Automatic Image Optimization, tersedia pada Next.js versi 10 keatas
- API Routes, membuat API tanpa library tambahan
Pada bagian ini kita akan bahas konsep-konsep yang ada di Next.js dengan cara membuat sebuah blog sebelum kita terapkan pada aplikasi DinoTes.
Step by step
Persiapan
Pastikan tool berikut ini sudah terinstall:
- Visual Studio Code
- Terminal
- Nodejs + NPM/yarn
Install Next JS
Untuk membuat sebuah aplikasi Next.js kita bisa gunakan package create-next-app, mirip dengan create-react-app.
Jalankan perintah berikut ini di terminal:
1$ npx create-next-app my-blog
Kemudian pindah folder dan jalankan aplikasi
1$ cd my-blog2$ yarn dev
Akses localhost:3000, jika tidak ada masalah kita akan dapatkan tampilan seperti ini:
Navigation
Setelah install ,yang akan kita lakukan adalah membuat halaman baru dan navigasi antar halaman.
Sistem routing pada Next.js adalah page-based, artinya setiap halaman memiliki alamat url (slug) sesuai dengan nama file dari halaman tersebut.
Contoh:
- Halaman pages/about.js dapat diakses dengan alamat url /about
- Halaman pages/posts/my-post.js dapat diakses dengan alamat url /posts/my-post
- Hal ini berbeda dengan aplikasi React dimana untuk membuat sistem routing kita harus gunakan package tambahan seperti react-router-dom.
Membuat halaman baru
Buat sebuah folder dengan nama posts kemudian buat sebuah file baru dengan nama first-post.js.
Susunan Folder:
Salin code berikut ini di dalam file first-post.js.
first-post.js
1export default function FirstPost() {2 return (3 <>4 <h1>First Post</h1>5 <p>6 Lorem Ipsum is simply dummy text of the printing and typesettingindustry. Lorem Ipsum has been the industry's7 standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make8 a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting,9 remaining essentially unchanged10 </p>11 </>12 );13}
Link antar halaman
Untuk membuat link antar halaman kita bisa gunakan component Link yang sudah disediakan oleh Next.js. Jadi kita tidak gunakan tag link .
Component Link ini juga akan mengaktifkan client-side navigation, dimana proses peralihan dari satu halaman ke halaman lain dilakukan oleh JavaScript dan bukan browser.
Update code halaman pages/index.js menjadi seperti ini:
index.js
1import Head from 'next/head';2import Link from 'next/link';3import styles from '../styles/Home.module.css';45export default function Home() {6 return (7 <div className={styles.container}>8 <Head>9 <title>Create Next App</title>10 <link rel="icon" href="/favicon.ico" />11 </Head>12 <main className={styles.main}>13 <h1 className={styles.title}>Welcome to My Blog</h1>14 <div className={styles.grid}>15 <div className={styles.card}>16 <Link href="/posts/first-post">17 <h3>First Post</h3>18 </Link>19 <p>Lorem Ipsum is simply dummy text of the printing and typesetting industry...</p>20 </div>21 </div>22 </main>23 <footer className={styles.footer}></footer>24 </div>25 );26}
Hasilnya:
Layout Components
Kita bisa membuat sebuah shared component yang bisa digunakan pada semua halaman lain dengan menggunakan Layout.
Caranya adalah dengan membuat sebuah folder dengan nama components kemudian buat sebuah file baru layout.js dengan code berikut ini:
1export default function Layout({ children }) {2 return <div>{children}</div>;3}
Kemudian import component ke dalam file first-post.js.
1import Layout from '../../components/layout';23export default function FirstPost() {4 return (5 <Layout>6 <h1>First Post</h1>7 // more8 </Layout>9 );10}
Untuk mengetahui kegunaan dari Layout component ini kita perlu buat satu halaman baru lagi.
Buat sebuah file dengan nama second-post.js di dalam folder posts dengan code sebagai berikut:
posts/second-post.js
1import Layout from '../../components/layout';23export default function SecondPost() {4 return (5 <Layout>6 <h1>Second Post</h1>7 <p>8 Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin9 literature from 45 BC, making it over 2000 years old10 </p>11 </Layout>12 );13}
Dengan layout component, setiap code yang ditambahkan ke file layout.js akan muncul di kedua halaman post.
Styles
Salah satu penggunaan layout component adalah menambahkan style CSS ke banyak halaman tanpa harus menambahkannya satu per-satu.
Kita akan tambahkan CSS ke semua halaman post…
Buat sebuah file dengan nama layout.module.css di dalam folder components.
Tambahkan code berikut ini:
layout.module.css
1.container {2 max-width: 36rem;3 padding: 0 1rem;4 margin: 3rem auto 6rem;5}
Kemudian update layout.js:
layout.js
1import styles from './layout.module.css';23export default function Layout({ children }) {4 return <div className={styles.container}>{children}</div>;5}
Hasilnya:
Global Styles
Sedangkan jika ingin menerapkan sebuah style ke semua halaman, gunakan Global Styles.
Untuk melakukannya kita update file styles/global.css.
Ubah ukuran default dari font dan line-height.
global.css
1html,2body {3 padding: 0;4 margin: 0;5 font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica6 Neue, sans-serif;7 line-height: 1.6;8 font-size: 18px;9}10a {11 color: inherit;12 text-decoration: none;13}14* {15 box-sizing: border-box;16}
Semua ukuran font pada blog sekarang berukuran 18px dengan jarak antar baris adalah 1.6.
Asset
Untuk menghandle asset seperti file gambar kita bisa simpan di dalam folder public.
Kita bisa akses file gambar cukup dengan menggunakan nama file tanpa path (relative path).
1<img src="/my-image.png" alt="My Image" className="logo" />
Hasil Akhir:
Pre-rendering
Next.js dapat melakukan dua bentuk pre-rendering yaitu SSR & SSG.
Teknik pre-rendering membuat load halaman menjadi lebih cepat dibanding dengan teknik tanpa pre-rendering.
Perbandingan
Rendering vs Pre-rendering
SSG vs SSR
SSG
Halaman HTML digenerate pada saat proses build sebelum dikirim ke client/client mengirimkan request.
SSR
Halaman HTML di generate untuk setiap request dari client.
Data Fetching
Next.js menggunakan function yang berbeda untuk proses data fetching pada setiap teknik pre-rendering:
Untuk SSG kita gunakan function getStaticProps.
Untuk SSR kita gunakan function getServerSideProps.
Pada bagian ini kita akan buat demo fetch data dari sebuah API menggunakan pre-rendering SSG.
Membuat API
Kita bisa gunakan package json-server untuk membuat API.
Install json-server
1$ yarn global add json-server
Atau
1$ npm install -g json-server
Buat sebuah file di dalam komputer/laptop dengan nama db.json.
Kemudian jalankan perintah berikut ini untuk start server.
1$ json-server --watch db.json --port 3001
Pastikan jalankan perintah ini dari dalam folder dimana db.json berada. Dan kita gunakan port 3001 karena port 3000 sudah digunakan oleh Next.js.
Implementasi getStaticProps
Tambah code berikut ini di bagian bawah component Home atau file index.js.
index.js
1...23export async function getStaticProps() {4 const apiURL = "http://localhost:3001/posts";5 const response = await fetch(apiURL);6 const data = await response.json();7 return {8 props: {9 externalPostData: data,10 },11 };12}
Props externalPostData dapat diakses di dalam component Home.
index.js
1...2export default function Home({ externalPostData }) {3...
Kemudian data kita render sebagai daftar post:
index.js
1...2 {externalPostData.map((data) => {3 return (4 <div className={styles.card} key={data.id}>5 <Link href={data.link}>6 <h3>{data.title}</h3>7 </Link>8 <p>{data.excerpt}</p>9 </div>10 );11 })}12...
Final Code dari index.js:
1import Head from "next/head";2import Link from "next/link";3import styles from "../styles/Home.module.css";45export default function Home({ externalPostData }) {6 return (7 <div className={styles.container}>8 <Head>9 <title>Create Next App</title>10 <link rel="icon" href="/favicon.ico" />11 </Head>1213 <main className={styles.main}>14 <img src="/my-image.png" alt="My Image" className="logo" />15 <h1 className={styles.title}>Welcome to My Blog</h1>1617 <div className={styles.grid}>18 <div className={styles.card}>19 <Link href="/posts/first-post">20 <h3>First Post</h3>21 </Link>22 <p>23 Lorem Ipsum is simply dummy text of the printing and typesetting24 industry...25 </p>26 </div>27 <div className={styles.card}>28 <Link href="/posts/second-post">29 <h3>Second Post</h3>30 </Link>31 <p>32 Contrary to popular belief, Lorem Ipsum is not simply random33 text...34 </p>35 </div>36 {externalPostData.map((data) => {37 return (38 <div className={styles.card} key={data.id}>39 <Link href={data.link}>40 <h3>{data.title}</h3>41 </Link>42 <p>{data.excerpt}</p>43 </div>44 );45 })}46 </div>47 </main>4849 <footer className={styles.footer}></footer>50 </div>51 );52}5354export async function getStaticProps() {55 const apiURL = "http://localhost:3001/posts";5657 const response = await fetch(apiURL);5859 const data = await response.json();6061 return {62 props: {63 externalPostData: data,64 },65 };66}
Hasilnya:
Data First Post dan Second Post berasal dari halaman internal atau file yang ada di dalam folder pages.
Sedangkan data Third Post dan Last Post berasal dari API/json-server.
Jika kita klik Third Post, Next.js akan mengarahkan ke alamat /posts/third-post, tetapi kita akan mendapatkan error seperti ini:
Hal ini dikarenakan halaman untuk menampilkan data tersebut belum dibuat.
Agar halaman dapat dibuat secara dinamis berdasarkan data yang didapat dari API kita bisa gunakan Dynamic Routes/URL.
Dynamic Routes/ URLs
Dengan dynamic routes kita bisa buat halaman berdasarkan external data seperti dari API.
Kita akan gunakan function bernama getStaticPaths untuk generate path yang dibutuhkan.
Buat sebuah file dengan nama [id].js di dalam folder pages/posts.
Kemudian tambahkan code berikut ini:
[id].js
1import Layout from '../../components/layout';23export default function Post() {4 return (5 <Layout>6 <h1></h1>7 <p></p>8 </Layout>9 );10}
Di file yang sama buat function untuk mendapatkan data semua id dari setiap post:
[id].js
1...2async function getAllPostIds() {3 const apiUrl = "http://localhost:3001/posts";45 const response = await fetch(apiUrl);67 const allPosts = await response.json();89 const allPostIds = allPosts.map((post) => {10 return { params: { id: post.alias } };11 });1213 return allPostIds;14}
Yang perlu diperhatikan disini adalah bentuk data yang dihasilkan oleh function harus memiliki format seperti ini:
1[2 {3 "params":{4 "id":"third-post"5 }6 },7 {8 "params":{9 "id":"last-post"10 }11 }12]
Harus memiliki params dan id untuk setiap objectnya.
Tanpa menggunakan format ini getStaticPaths akan gagal dieksekusi.
Tambahkan function getStaticPaths:
[id].js
1...2export async function getStaticPaths() {3 const paths = await getAllPostIds();4 return {5 paths,6 fallback: false,7 };8}
Kemudian tambahkan function untuk mendapatkan data tunggal dari post dengan parameter alias:
[id].js
1async function getPostData(id) {2 const apiURL = `http://localhost:3001/posts?alias=${id}`;34 const response = await fetch(apiURL);56 const postData = await response.json();78 return postData;9}
Function di atas akan digunakan di dalam function getStaticProps:
[id].js
1...2export async function getStaticProps({ params }) {3 const postData = await getPostData(params.id);4 return {5 props: {6 postData: postData[0],7 },8 };9}
Jika kita menggunakan json-server, data dikirimkan dalam bentuk array, oleh karena itu untuk membaca data kita harus akses index array ke-0.
postData: postData[0]
Terakhir update component Post untuk menampilkan data dari getStaticProps:
[id].js
1export default function Post({ postData }) {2 return (3 <Layout>4 <h1>{ postData.title }</h1>5 <p>{ postData.body }</p>6 </Layout>7 );8}910...
Final Code:
[id].js
1import Layout from "../../components/layout";23export default function Post({ postData }) {4 return (5 <Layout>6 <h1>{ postData.title }</h1>7 <p>{ postData.body }</p>8 </Layout>9 );10}1112async function getAllPostIds() {13 const apiUrl = "http://localhost:3001/posts";1415 const response = await fetch(apiUrl);1617 const allPosts = await response.json();1819 const allPostIds = allPosts.map((post) => {20 return { params: { id: post.alias } };21 });2223 return allPostIds;24}2526export async function getStaticPaths() {27 const paths = await getAllPostIds();28 return {29 paths,30 fallback: false,31 };32}3334async function getPostData(id) {35 const apiURL = `http://localhost:3001/posts?alias=${id}`;3637 const response = await fetch(apiURL);3839 const postData = await response.json();4041 return postData;42}4344export async function getStaticProps({ params }) {45 const postData = await getPostData(params.id);46 return {47 props: {48 postData: postData[0],49 },50 };51}
Hasilnya:
Deployment
Ada beberapa tempat hosting yang bisa kita gunakan untuk deploy aplikasi next.js secara gratis. Dan yang paling mudah adalah menggunakan platform Vercel.
Team Vercel adalah creator Next.js.
Proses Deploy:
- Buat akun di Vercel
- Push repository ke github
- Import repository menggunakan menu New Project
Vercel akan mendeteksi semua konfigurasi secara otomatis untuk selanjutnya di deploy. Setelah proses deploy berhasil, kita akan mendapatkan url untuk mengakses aplikasi Next.js.
Lainnya
Masih ada beberapa fitur dasar Next.js yang tidak dicover di dalam tutorial ini, seperti:
- API Routes
- Image optimization
- Environment Variable
- TypeScript Support
Untuk lebih lengkapnya kamu bisa akses halaman offical Next.js.