Dokumentasi lengkap tentang sistem routing di OurCreativity
OurCreativity menggunakan React Router v6 dengan BrowserRouter untuk navigasi client-side dengan URL yang persisten dan shareable.
Mengapa BrowserRouter?
- ✅ URL yang persisten dan dapat dibookmark
- ✅ Mendukung deep linking (langsung ke halaman spesifik)
- ✅ URL dapat dibagikan ke pengguna lain
- ✅ SEO-friendly (dengan SSR/SSG di masa depan)
- ✅ Browser history navigation (tombol back/forward)
Trade-off:
⚠️ Memerlukan konfigurasi server untuk SPA fallback⚠️ Harus handle 404 dengan benar pada level server
<BrowserRouter>
<Routes>
{/* Halaman Utama */}
<Route path="/" element={<Home />} />
{/* Halaman Fitur */}
<Route path="/karya" element={<Karya />} />
<Route path="/tim" element={<Tim />} />
<Route path="/story" element={<Story />} />
<Route path="/info" element={<Info />} />
<Route path="/announcement" element={<Announcement />} />
{/* Halaman Divisi */}
<Route path="/division/graphics" element={<Graphics />} />
<Route path="/division/video" element={<VideoPage />} />
<Route path="/division/writing" element={<Writing />} />
<Route path="/division/meme" element={<Meme />} />
<Route path="/division/coding" element={<Coding />} />
{/* Fallback 404 */}
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</BrowserRouter>Semua halaman kecuali Home dimuat secara lazy untuk optimasi performa:
// Home dimuat eagerly (langsung)
import { Home } from './pages/Home';
// Halaman lain dimuat lazy
const Karya = React.lazy(() =>
import('./pages/Karya').then(module => ({ default: module.Karya }))
);
const Tim = React.lazy(() =>
import('./pages/Tim').then(module => ({ default: module.Tim }))
);
// ... dstManfaat:
- Reduced initial bundle size
- Faster first paint
- Better Core Web Vitals
Loading Fallback:
<Suspense fallback={<Loading />}>
<Routes>...</Routes>
</Suspense>Otomatis scroll ke atas saat navigasi:
const ScrollToTop = () => {
const { pathname } = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);
return null;
};Menggunakan Framer Motion AnimatePresence:
<AnimatePresence mode="wait">
<motion.div key={location.pathname}>
<Routes location={location}>...</Routes>
</motion.div>
</AnimatePresence>Semua rute dibungkus dengan ErrorBoundary:
<ErrorBoundary>
<Suspense fallback={<Loading />}>
<Routes>...</Routes>
</Suspense>
</ErrorBoundary>PENTING: Karena client-side routing, server harus mengarahkan semua request ke index.html.
File vercel.json di root:
{
"rewrites": [
{ "source": "/(.*)", "destination": "/index.html" }
]
}Opsi 1: File netlify.toml di root:
[build]
command = "npm run build"
publish = "dist"
[[redirects]]
from = "/*"
to = "/index.html"
status = 200Opsi 2: File _redirects di folder public/:
/* /index.html 200
File _redirects di folder public/:
/* /index.html 200
File .htaccess:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>Konfigurasi server block:
location / {
try_files $uri $uri/ /index.html;
}import { Link } from 'react-router-dom';
<Link to="/karya">Lihat Karya</Link>import { useNavigate } from 'react-router-dom';
function MyComponent() {
const navigate = useNavigate();
const handleClick = () => {
navigate('/tim');
};
return <button onClick={handleClick}>Tim</button>;
}import { Navigate } from 'react-router-dom';
<Route path="*" element={<Navigate to="/" replace />} />❌ Jangan:
<a href="/karya">Karya</a>✅ Lakukan:
<Link to="/karya">Karya</Link>Home page dimuat eagerly, sisanya lazy:
// Eager
import { Home } from './pages/Home';
// Lazy
const Karya = React.lazy(() => import('./pages/Karya'));Selalu berikan fallback untuk lazy routes:
<Suspense fallback={<LoadingSpinner />}>
<Routes>...</Routes>
</Suspense>Tangani error routing dengan ErrorBoundary:
<ErrorBoundary fallback={<ErrorPage />}>
<Routes>...</Routes>
</ErrorBoundary>npm run devServer dev Vite sudah dikonfigurasi untuk handle SPA routing.
npm run build
npm run previewPreview server juga sudah dikonfigurasi untuk SPA fallback.
Gejala: Navigasi works, tapi refresh halaman returns 404.
Solusi: Pastikan SPA fallback config sudah terpasang di server hosting.
Gejala: CSS/JS tidak load setelah navigasi.
Solusi: Check base config di vite.config.ts:
export default defineConfig({
base: '/', // untuk root domain
// base: '/subfolder/', // untuk subfolder
})Gejala: Infinite loading atau error saat navigasi.
Solusi:
- Check console untuk module import errors
- Pastikan export named di page module:
export const Karya = () => { ... }
- Import dengan named export:
React.lazy(() => import('./pages/Karya').then(m => ({ default: m.Karya })))
Jika upgrade dari versi lama yang pakai MemoryRouter:
-
Update import di
App.tsx:// Sebelum import { MemoryRouter } from 'react-router-dom'; // Sesudah import { BrowserRouter } from 'react-router-dom';
-
Deploy dengan SPA fallback config
-
Test semua routes:
- Direct navigation (klik link)
- Refresh page
- Back/forward browser
- Deep link (paste URL)
Terakhir Diperbarui: November 2025
Versi: 5.0
Pemelihara: Tim OurCreativity