Monday

18-08-2025 Vol 19

npx create-react19-app@latest my-app: a multi-page (file based routing) SSR React 19 app

Membuat Aplikasi React 19 SSR Multi-Halaman dengan Routing Berbasis File: Panduan Lengkap

React 19 menjanjikan banyak peningkatan, termasuk dukungan SSR (Server-Side Rendering) yang ditingkatkan dan routing berbasis file yang lebih mudah. Panduan ini akan memandu Anda melalui proses pembuatan aplikasi React 19 SSR multi-halaman menggunakan npx create-react19-app@latest my-app, memastikan Anda memahami setiap langkah di sepanjang jalan.

Daftar Isi

  1. Pendahuluan: Mengapa React 19 dan SSR?
  2. Prasyarat: Memastikan Anda Siap
  3. Langkah 1: Membuat Proyek React 19 Baru
  4. Langkah 2: Memahami Struktur Proyek
  5. Langkah 3: Implementasi Routing Berbasis File
    1. Membuat Direktori pages
    2. Membuat Rute Dasar
    3. Membuat Rute Dinamis
    4. Menangani 404 (Halaman Tidak Ditemukan)
  6. Langkah 4: Mengimplementasikan Server-Side Rendering (SSR)
    1. Konfigurasi Server
    2. Mengambil Data di Server
    3. Menyediakan Data ke Klien
  7. Langkah 5: Mengoptimalkan Aplikasi untuk Produksi
    1. Minifikasi dan Bundling
    2. Konfigurasi Caching
    3. Menangani SEO
  8. Langkah 6: Menerapkan Aplikasi React 19 SSR Anda
  9. Pemecahan Masalah Umum
  10. Praktik Terbaik untuk Pengembangan Aplikasi React 19 SSR
  11. Kesimpulan: Masa Depan Aplikasi React dengan SSR dan Routing Berbasis File

1. Pendahuluan: Mengapa React 19 dan SSR?

React telah menjadi salah satu framework JavaScript paling populer untuk membangun antarmuka pengguna. Dengan setiap rilis baru, React terus berkembang, memperkenalkan fitur-fitur baru dan meningkatkan kinerja. React 19 menjanjikan peningkatan signifikan, khususnya dalam hal Server-Side Rendering (SSR) dan kemudahan routing.

Mengapa SSR penting?

  1. Peningkatan SEO: Mesin pencari dapat merayapi dan mengindeks konten Anda dengan lebih efektif karena HTML sepenuhnya dirender di server.
  2. Waktu Pemuatan Lebih Cepat: Pengguna melihat konten yang dirender lebih cepat, meningkatkan pengalaman pengguna dan mengurangi rasio pentalan.
  3. Pengalaman Pengguna yang Lebih Baik: Aplikasi Anda terasa lebih responsif karena konten awal ditampilkan dengan cepat, meskipun JavaScript belum sepenuhnya dimuat.

Routing berbasis file menyederhanakan proses penentuan rute dalam aplikasi Anda. Daripada mengonfigurasi rute secara manual, Anda cukup membuat file di direktori tertentu, dan rute akan dibuat secara otomatis berdasarkan nama file.

2. Prasyarat: Memastikan Anda Siap

Sebelum kita mulai, pastikan Anda memiliki alat berikut yang terinstal:

  1. Node.js: React membutuhkan Node.js untuk menjalankan development server dan membangun aplikasi Anda. Unduh dan instal versi terbaru dari situs web resmi Node.js.
  2. npm atau Yarn: npm (Node Package Manager) hadir dengan Node.js. Anda juga dapat menggunakan Yarn, manajer paket alternatif.
  3. Text Editor atau IDE: Pilih editor kode yang Anda sukai. Visual Studio Code, Sublime Text, dan Atom adalah pilihan populer.

3. Langkah 1: Membuat Proyek React 19 Baru

Buka terminal Anda dan jalankan perintah berikut untuk membuat proyek React 19 baru:

npx create-react-app@latest my-app
cd my-app

Perintah ini akan membuat direktori bernama my-app dan menginisialisasi proyek React di dalamnya. create-react-app secara otomatis mengkonfigurasi sebagian besar hal yang perlu Anda kerjakan, jadi ini adalah cara yang cepat dan mudah untuk memulai.

Setelah proyek dibuat, navigasikan ke direktori proyek:

cd my-app

Sekarang, Anda dapat memulai development server:

npm start

Ini akan membuka aplikasi React Anda di browser Anda. Anda akan melihat halaman selamat datang React default.

4. Langkah 2: Memahami Struktur Proyek

Sebelum kita mulai mengimplementasikan routing berbasis file dan SSR, mari kita pahami struktur proyek React yang dibuat oleh create-react-app.

my-app/
├── node_modules/
├── public/
│   ├── index.html
│   └── ...
├── src/
│   ├── App.js
│   ├── App.css
│   ├── index.js
│   ├── index.css
│   ├── logo.svg
│   └── ...
├── package.json
├── README.md
└── ...
  1. node_modules/: Direktori ini berisi semua dependensi yang diinstal oleh npm atau Yarn.
  2. public/: Direktori ini berisi aset statis seperti index.html.
  3. src/: Direktori ini berisi kode sumber React Anda.
    • App.js: Komponen aplikasi utama.
    • index.js: Titik masuk untuk aplikasi React Anda.
  4. package.json: File ini berisi metadata tentang proyek Anda, termasuk dependensi dan skrip.

5. Langkah 3: Implementasi Routing Berbasis File

Routing berbasis file memungkinkan Anda menentukan rute berdasarkan struktur direktori aplikasi Anda. Kami akan membuat direktori pages untuk menyimpan komponen halaman kami.

5.1. Membuat Direktori pages

Buat direktori pages di dalam direktori src:

mkdir src/pages

5.2. Membuat Rute Dasar

Sekarang, mari kita buat beberapa rute dasar. Di dalam direktori pages, buat file berikut:

  • src/pages/index.js: Halaman beranda.
  • src/pages/about.js: Halaman tentang.
  • src/pages/contact.js: Halaman kontak.

Berikut adalah contoh kode untuk setiap halaman:

src/pages/index.js:

import React from 'react';

function HomePage() {
  return (
    <div>
      <h1>Beranda</h1>
      <p>Selamat datang di beranda!</p>
    </div>
  );
}

export default HomePage;

src/pages/about.js:

import React from 'react';

function AboutPage() {
  return (
    <div>
      <h1>Tentang</h1>
      <p>Ini adalah halaman tentang.</p>
    </div>
  );
}

export default AboutPage;

src/pages/contact.js:

import React from 'react';

function ContactPage() {
  return (
    <div>
      <h1>Kontak</h1>
      <p>Ini adalah halaman kontak.</p>
    </div>
  );
}

export default ContactPage;

Untuk menampilkan halaman-halaman ini, Anda perlu memperbarui App.js untuk menggunakan router yang mendukung routing berbasis file. Karena create-react-app tidak menyertakan router secara default, kita harus menginstal salah satu. Untuk contoh ini, kita akan menggunakan react-router-dom.

npm install react-router-dom

Sekarang, perbarui src/App.js dengan kode berikut:

import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import HomePage from './pages/index';
import AboutPage from './pages/about';
import ContactPage from './pages/contact';

function App() {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li><a href="/">Beranda</a></li>
            <li><a href="/about">Tentang</a></li>
            <li><a href="/contact">Kontak</a></li>
          </ul>
        </nav>

        <Switch>
          <Route path="/" exact>
            <HomePage />
          </Route>
          <Route path="/about">
            <AboutPage />
          </Route>
          <Route path="/contact">
            <ContactPage />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

export default App;

Kode ini menggunakan react-router-dom untuk menentukan rute. Komponen <Router> membungkus seluruh aplikasi, dan komponen <Route> menentukan rute untuk setiap halaman.

5.3. Membuat Rute Dinamis

Rute dinamis memungkinkan Anda membuat rute yang cocok dengan pola tertentu. Misalnya, Anda dapat membuat rute untuk menampilkan detail posting blog berdasarkan ID posting.

Buat file bernama src/pages/blog/[id].js:

mkdir src/pages/blog
touch src/pages/blog/[id].js

Perhatikan penggunaan tanda kurung siku ([]) dalam nama file. Ini menunjukkan bahwa id adalah parameter dinamis.

Berikut adalah contoh kode untuk src/pages/blog/[id].js:

import React from 'react';
import { useParams } from 'react-router-dom';

function BlogPost() {
  const { id } = useParams();

  return (
    <div>
      <h1>Posting Blog: {id}</h1>
      <p>Ini adalah detail posting blog dengan ID: {id}</p>
    </div>
  );
}

export default BlogPost;

Kode ini menggunakan useParams hook dari react-router-dom untuk mengakses parameter id dari URL. Misalnya, jika Anda mengunjungi /blog/123, komponen BlogPost akan menampilkan “Posting Blog: 123”.

Perbarui App.js untuk menyertakan rute dinamis:

import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import HomePage from './pages/index';
import AboutPage from './pages/about';
import ContactPage from './pages/contact';
import BlogPost from './pages/blog/[id]'; // Import the BlogPost component

function App() {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li><a href="/">Beranda</a></li>
            <li><a href="/about">Tentang</a></li>
            <li><a href="/contact">Kontak</a></li>
            <li><a href="/blog/123">Blog Post 123</a></li>
          </ul>
        </nav>

        <Switch>
          <Route path="/" exact>
            <HomePage />
          </Route>
          <Route path="/about">
            <AboutPage />
          </Route>
          <Route path="/contact">
            <ContactPage />
          </Route>
          <Route path="/blog/:id">
            <BlogPost />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

export default App;

Perhatikan bahwa kita menggunakan :id dalam path prop dari komponen <Route> untuk rute dinamis. Ini memberi tahu react-router-dom untuk mencocokkan setiap URL yang dimulai dengan /blog/ dan mengekstrak segmen setelahnya sebagai parameter id.

5.4. Menangani 404 (Halaman Tidak Ditemukan)

Penting untuk menangani kasus ketika pengguna mengunjungi URL yang tidak ada. Anda dapat membuat komponen 404 khusus dan menampilkannya ketika tidak ada rute lain yang cocok.

Buat file bernama src/pages/404.js:

import React from 'react';

function NotFoundPage() {
  return (
    <div>
      <h1>404 - Halaman Tidak Ditemukan</h1>
      <p>Halaman yang Anda cari tidak ada.</p>
    </div>
  );
}

export default NotFoundPage;

Perbarui App.js untuk menyertakan komponen NotFoundPage:

import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import HomePage from './pages/index';
import AboutPage from './pages/about';
import ContactPage from './pages/contact';
import BlogPost from './pages/blog/[id]';
import NotFoundPage from './pages/404';

function App() {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li><a href="/">Beranda</a></li>
            <li><a href="/about">Tentang</a></li>
            <li><a href="/contact">Kontak</a></li>
            <li><a href="/blog/123">Blog Post 123</a></li>
          </ul>
        </nav>

        <Switch>
          <Route path="/" exact>
            <HomePage />
          </Route>
          <Route path="/about">
            <AboutPage />
          </Route>
          <Route path="/contact">
            <ContactPage />
          </Route>
          <Route path="/blog/:id">
            <BlogPost />
          </Route>
          <Route>
            <NotFoundPage />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

export default App;

Perhatikan bahwa komponen <Route> untuk NotFoundPage tidak memiliki path prop. Ini berarti bahwa ia akan cocok dengan setiap URL yang tidak cocok dengan rute lain. Ini harus menjadi rute terakhir di dalam komponen <Switch>.

6. Langkah 4: Mengimplementasikan Server-Side Rendering (SSR)

Sekarang setelah kita menyiapkan routing berbasis file, mari kita implementasikan Server-Side Rendering (SSR). SSR melibatkan rendering komponen React Anda di server dan mengirimkan HTML yang dirender ke klien. Ini meningkatkan SEO dan waktu pemuatan halaman awal.

6.1. Konfigurasi Server

Untuk mengimplementasikan SSR, kita perlu menyiapkan server. Kita akan menggunakan Express.js, framework Node.js yang populer.

npm install express react-dom

Buat file bernama server.js di direktori akar proyek Anda:

touch server.js

Berikut adalah contoh kode untuk server.js:

import express from 'express';
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import App from './src/App';
import path from 'path';
import fs from 'fs';

const app = express();
const PORT = process.env.PORT || 3000;

app.use(express.static('public'));

app.get('*', (req, res) => {
  const context = {};

  const appHtml = ReactDOMServer.renderToString(
    <StaticRouter location={req.url} context={context}>
      <App />
    </StaticRouter>
  );

  const indexFile = path.resolve('./public/index.html');

  fs.readFile(indexFile, 'utf8', (err, data) => {
    if (err) {
      console.error('Something went wrong:', err);
      return res.status(500).send('Oops, better luck next time!');
    }

    data = data.replace('<div id="root"></div>', `<div id="root">${appHtml}</div>`);
    res.send(data);
  });
});

app.listen(PORT, () => {
  console.log(`Server is listening on port ${PORT}`);
});

Kode ini melakukan hal berikut:

  1. Mengimpor modul yang diperlukan.
  2. Membuat aplikasi Express.
  3. Menentukan port untuk server.
  4. Menyajikan file statis dari direktori public.
  5. Menangani semua permintaan GET.
    • Merender komponen App ke string menggunakan ReactDOMServer.renderToString.
    • Membaca file index.html.
    • Mengganti <div id="root"></div> dengan HTML yang dirender.
    • Mengirimkan HTML yang dimodifikasi ke klien.
  6. Memulai server.

Perhatikan penggunaan StaticRouter. Ini adalah versi khusus dari BrowserRouter yang digunakan untuk SSR. Ia mengambil URL dari objek permintaan dan menyediakannya ke aplikasi React.

Selain itu, kita menggunakan ReactDOMServer.renderToString untuk merender komponen App ke string. Ini menghasilkan HTML yang dapat dikirim ke klien.

Kita juga perlu sedikit memodifikasi file index.js:

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render();

Tambahkan skrip berikut ke bagian “scripts” di package.json:

"start:server": "node server.js",
"build": "webpack --mode production",
"start": "npm run build && npm run start:server"

Sekarang Anda dapat memulai server menggunakan perintah berikut:

npm start

Ini akan memulai server dan aplikasi React Anda akan dirender di server.

6.2. Mengambil Data di Server

Dalam banyak kasus, Anda perlu mengambil data dari API atau database sebelum merender komponen Anda. Untuk melakukan ini di server, Anda dapat menggunakan fungsi getInitialProps.

Contoh, perbarui src/pages/about.js:

import React, { useState, useEffect } from 'react';

function AboutPage() {
  const [data, setData] = useState(null);

  useEffect(() => {
    async function fetchData() {
      const res = await fetch('https://jsonplaceholder.typicode.com/todos/1');
      const json = await res.json();
      setData(json);
    }

    fetchData();
  }, []);

  return (
    <div>
      <h1>Tentang</h1>
      <p>Ini adalah halaman tentang.</p>
      {data && <p>Data dari API: {data.title}</p>}
    </div>
  );
}

export default AboutPage;

Pada contoh diatas, kita mengambil data dari API menggunakan `useEffect`. Akan tetapi, data tersebut hanya akan didapatkan setelah komponen di render di browser. Untuk melakukan SSR dengan data, kita perlu memodifikasi server kita.

Modifikasi server.js:

import express from 'express';
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import App from './src/App';
import path from 'path';
import fs from 'fs';

const app = express();
const PORT = process.env.PORT || 3000;

app.use(express.static('public'));

async function fetchData() {
    const res = await fetch('https://jsonplaceholder.typicode.com/todos/1');
    const json = await res.json();
    return json;
}

app.get('*', async (req, res) => {
  const context = {};
  const data = await fetchData(); // Fetch data here

  const appHtml = ReactDOMServer.renderToString(
    <StaticRouter location={req.url} context={context}>
      <App initialData={data}/>
    </StaticRouter>
  );

  const indexFile = path.resolve('./public/index.html');

  fs.readFile(indexFile, 'utf8', (err, data) => {
    if (err) {
      console.error('Something went wrong:', err);
      return res.status(500).send('Oops, better luck next time!');
    }

    data = data.replace('<div id="root"></div>', `<div id="root">${appHtml}</div>`);
    res.send(data);
  });
});

app.listen(PORT, () => {
  console.log(`Server is listening on port ${PORT}`);
});

Modifikasi App.js:

import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import HomePage from './pages/index';
import AboutPage from './pages/about';
import ContactPage from './pages/contact';
import BlogPost from './pages/blog/[id]';
import NotFoundPage from './pages/404';

function App({initialData}) {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li><a href="/">Beranda</a></li>
            <li><a href="/about">Tentang</a></li>
            <li><a href="/contact">Kontak</a></li>
            <li><a href="/blog/123">Blog Post 123</a></li>
          </ul>
        </nav>

        <Switch>
          <Route path="/" exact>
            <HomePage />
          </Route>
          <Route path="/about">
            <AboutPage initialData={initialData}/>
          </Route>
          <Route path="/contact">
            <ContactPage />
          </Route>
          <Route path="/blog/:id">
            <BlogPost />
          </Route>
          <Route>
            <NotFoundPage />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

export default App;

Modifikasi AboutPage.js:

import React from 'react';

function AboutPage({initialData}) {

  return (
    <div>
      <h1>Tentang</h1>
      <p>Ini adalah halaman tentang.</p>
      {initialData && <p>Data dari API: {initialData.title}</p>}
    </div>
  );
}

export default AboutPage;

Pada contoh diatas, data sudah ada sebelum browser melakukan render dan menampilkan data yang sudah ada. Hal ini meningkatkan performa aplikasi kita.

6.3. Menyediakan Data ke Klien

Kita telah mengambil data di server dan merender komponen kita dengan data tersebut. Sekarang kita perlu menyediakan data ini ke klien agar klien tidak perlu mengambil data lagi.

Untuk melakukan ini, kita dapat menyertakan data dalam HTML yang dirender sebagai variabel JavaScript. Kemudian, klien dapat membaca variabel ini dan menggunakannya untuk menginisialisasi komponen kita.

Ubah kode server.js anda:

import express from 'express';
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import App from './src/App';
import path from 'path';
import fs from 'fs';

const app = express();
const PORT = process.env.PORT || 3000;

app.use(express.static('public'));

async function fetchData() {
    const res = await fetch('https://jsonplaceholder.typicode.com/todos/1');
    const json = await res.json();
    return json;
}

app.get('*', async (req, res) => {
  const context = {};
  const data = await fetchData(); // Fetch data here
  const serializedData = JSON.stringify(data);

  const appHtml = ReactDOMServer.renderToString(
    <StaticRouter location={req.url} context={context}>
      <App initialData={data}/>
    </StaticRouter>
  );

  const indexFile = path.resolve('./public/index.html');

  fs.readFile(indexFile, 'utf8', (err, data) => {
    if (err) {
      console.error('Something went wrong:', err);
      return res.status(500).send('Oops, better luck next time!');
    }

    data = data.replace('<div id="root"></div>', `<div id="root">${appHtml}</div>
                                                        <script>
                                                          window.__INITIAL_DATA__ = ${serializedData};
                                                        </script>`);
    res.send(data);
  });
});

app.listen(PORT, () => {
  console.log(`Server is listening on port ${PORT}`);
});

Lalu modifikasi AboutPage.js:

import React from 'react';

function AboutPage({initialData}) {
    const data = initialData || window.__INITIAL_DATA__;

  return (
    <div>
      <h1>Tentang</h1>
      <p>Ini adalah halaman tentang.</p>
      {data && <p>Data dari API: {data.title}</p>}
    </div>
  );
}

export default AboutPage;

Sekarang, data akan tersedia untuk klien saat halaman dimuat.

7. Langkah 5: Mengoptimalkan Aplikasi untuk Produksi

Sebelum menerapkan aplikasi Anda ke produksi, penting untuk mengoptimalkannya untuk kinerja. Ini termasuk:

7.1. Minifikasi dan Bundling

Minifikasi dan bundling mengurangi ukuran kode JavaScript Anda dengan menghapus ruang kosong dan menggabungkan beberapa file menjadi satu. create-react-app secara otomatis menangani hal ini saat Anda menjalankan perintah npm run build.

7.2. Konfigurasi Caching

Caching memungkinkan browser untuk menyimpan aset statis Anda sehingga mereka tidak perlu mengunduhnya setiap kali pengguna mengunjungi halaman Anda. Anda dapat mengonfigurasi caching menggunakan header HTTP atau service worker.

7.3. Menangani SEO

SEO (Search Engine Optimization) penting untuk membuat aplikasi Anda mudah ditemukan oleh mesin pencari. Beberapa tips SEO meliputi:

  1. Gunakan judul dan deskripsi yang deskriptif untuk halaman Anda.
  2. Gunakan tajuk yang relevan (<h1>, <h2>, dll.) untuk struktur konten Anda.
  3. Sediakan teks alternatif untuk gambar Anda.
  4. Gunakan URL yang ramah SEO.

8. Langkah 6: Menerapkan Aplikasi React 19 SSR Anda

Setelah Anda mengoptimalkan aplikasi Anda, Anda dapat menerapkannya ke berbagai platform, seperti:

  1. Netlify: Platform yang mudah digunakan untuk menerapkan situs web statis dan aplikasi SSR.
  2. Vercel: Platform lain yang populer untuk menerapkan aplikasi Next.js dan React.
  3. AWS: Amazon Web Services menawarkan berbagai layanan untuk penerapan, seperti EC2, S3, dan CloudFront.
  4. Heroku: Platform cloud yang mendukung berbagai bahasa dan framework.

9. Pemecahan Masalah Umum

Berikut adalah beberapa masalah umum yang mungkin Anda hadapi saat mengembangkan aplikasi React 19 SSR:

  1. Ketidakcocokan Hydration: Ini terjadi ketika HTML yang dirender server tidak cocok dengan HTML yang dirender klien. Pastikan bahwa lingkungan server dan klien Anda dikonfigurasi dengan benar dan bahwa Anda menggunakan versi pustaka yang sama di kedua sisi.
  2. Kesalahan “window is not defined”: Kesalahan ini terjadi ketika Anda mencoba mengakses objek window di server. Objek window hanya tersedia di browser. Untuk mengatasi masalah ini, Anda dapat menggunakan pemeriksaan kondisi untuk memastikan bahwa Anda hanya mengakses objek window di klien.
  3. Masalah Routing: Pastikan bahwa rute Anda dikonfigurasi dengan benar di server dan klien. Gunakan StaticRouter untuk SSR dan BrowserRouter untuk perutean sisi klien

omcoding

Leave a Reply

Your email address will not be published. Required fields are marked *