⚛️ Frontend Engineering — React, Next.js, Component Architecture & State Management

Vault belum punya catatan soal frontend engineering sama sekali — padahal elo manage beberapa repo Next.js di MspUrbansolv (FE untuk asia-be, insite-be, dri-triplet-be). Catatan ini mengisi celah fundamental: component architecture patterns di React, state management (dari useState sampai Zustand/Redux), rendering strategy (CSR vs SSR vs SSG vs ISR vs RSC), CSS architecture, dan Next.js App Router vs Pages Router. Tanpa fondasi ini, frontend codebase cenderung jadi spaghetti component dengan state yang bocor ke mana-mana.

Posisi di Vault

Ini adalah domain baru di vault — Frontend Engineering. Terkait dengan software-engineering (prinsip software umum), clean-code-robert-martin (code quality), api-security-deep-dive (frontend security), cicd-guide (frontend CI/CD), dan web-security (XSS/CSP).


Daftar Isi


1. Component Architecture — Composition over Inheritance

1.1 Evolution of React Patterns

2014: Mixins (deprecated)
2015: createClass → ES6 class components
2016: Higher-Order Components (HOC) — withRouter(), connect()
2018: Render Props — <DataProvider render={...} />
2019: Hooks — useState, useEffect, custom hooks ← TODAY's default
2021: Server Components (RSC) — async component, zero client JS
2024+: React Server Components (stable) + Server Actions

1.2 Modern Component Patterns

PatternKapan DipakaiContoh
Atomic DesignDesign system skala besaratoms → molecules → organisms → templates → pages
Compound ComponentsComponent dengan internal state sharing<Select><Select.Option>, <Select.Label>
Container/PresentationalPisah logic dari UIContainer: fetching + state → Presentational: render only
Custom HooksReusable stateful logicuseAuth(), useDebounce(), useWebSocket()
Render PropsBehavior sharing tanpa state<MouseTracker render={(pos) => ...} />
Slots (children)Layout injection<Card header={<Header/>} footer={<Footer/>}>

1.3 Component Composition Examples

// Atomic Design: Molecule
interface InputFieldProps {
  label: string
  error?: string
  icon?: React.ReactNode
}
 
function InputField({ label, error, icon }: InputFieldProps) {
  return (
    <div className="input-field">
      <label className="input-field__label">{label}</label>
      <div className="input-field__wrapper">
        {icon && <span className="input-field__icon">{icon}</span>}
        <input className={`input-field__input ${error ? "input-field__input--error" : ""}`} />
      </div>
      {error && <span className="input-field__error">{error}</span>}
    </div>
  )
}
 
// Compound Component: Tabs
function Tabs({ children }: { children: React.ReactNode }) {
  const [active, setActive] = useState(0)
  return (
    <TabsContext.Provider value={{ active, setActive }}>
      <div className="tabs">{children}</div>
    </TabsContext.Provider>
  )
}
Tabs.List = function List({ children }: { children: React.ReactNode }) {
  return <div className="tabs__list">{children}</div>
}
Tabs.Panel = function Panel({ index, children }: { index: number; children: React.ReactNode }) {
  const { active } = useContext(TabsContext)
  return active === index ? <div className="tabs__panel">{children}</div> : null
}

1.4 Component Design Principles

Single Responsibility — Satu component, satu tanggung jawab
  ✅ <UserProfileCard>
  ❌ <UserProfileCardAndSettingsAndNotifications>

Props API Design:
  ✅ Explicit props: <Button variant="primary" size="md" disabled>
  ❌ Config object: <Button config={{ variant: 'primary', size: 'md' }}>

Don't Repeat Yourself:
  Extract repeated JSX + logic → custom component + custom hook

You Aren't Gonna Need It (YAGNI):
  Jangan bikin generic component yang bisa handle 100 use case
  Kalau cuma dipake di 2 tempat, hardcode aja dulu

2. State Management — Local sampai Global

2.1 State Categories

CategoryContohSolusi
Local UI stateModal open/close, form inputuseState, useReducer
Server stateData dari API (users, orders)TanStack Query, SWR
Global UI stateTheme, sidebar collapseZustand, Jotai, Context
URL stateSearch params, filtersuseSearchParams, Next.js router
Form stateForm values, validationReact Hook Form, Formik

2.2 State Management Tool Comparison

ToolBundle SizeBoilerplatePerformanceDevToolsBest For
useState0 KBMinimal🟢Local component state
useReducer0 KBSedang🟢Complex local state
Context API0 KBMinimal🟡 (re-render)Low-frequency global state
Zustand1.1 KBMinimal🟢Medium global state
Jotai3.3 KBMinimal🟢 (atomic)Atomic derived state
Redux Toolkit11 KBTinggi (slices)🟢Large-scale global state
TanStack Query13 KBMinimal🟢🟢Server state (API cache)

2.3 Practical Recommendations

Small app / MVP:
  useState + Context + TanStack Query → cukup untuk 95% kasus
 
Medium app (dashboard admin):
  Zustand untuk UI state + TanStack Query untuk server state
  → Zustand: < 1KB, no boilerplate, no Provider wrapping
 
Large app (enterprise, 50+ pages):
  Redux Toolkit + RTK Query — boilerplate tinggi
  Tapi devtools, middleware, ecosystem sepadan untuk skala tim besar
 
Rules of thumb:
  - Kalau state cuma dipake 1 component → useState
  - Kalau dipake 2-3 sibling → lifted state atau Context
  - Kalau dipake banyak component di beda branch → Zustand/Redux
  - Query param state → URL search params (bisa di-share via link)

3. Rendering Patterns — CSR, SSR, SSG, ISR, RSC

3.1 Comparison Matrix

PatternRender LocationFirst PaintSEOTTFBInteractivityFresh Data
CSR (Create React App)Browser🟡 Slow❌ Bad🟢 Fast🟢 Fast🟢 Always fresh
SSR (Next.js Pages Router)Server + Browser🟢 Fast✅ Good🟡 Slower🟡 Hydration delay🟡 Per request
SSG (static export)Build time🟢🟢 Instant✅ Best🟢 Fast🟢 Fast❌ Stale on deploy
ISR (Incremental)Build + on-demand🟢 Fast✅ Best🟢 Fast🟢 Fast🟡 Revalidation lag
RSC (App Router)Server🟢 Fast✅ Best🟢 Fast🟢 Fast🟢 Per request

3.2 Next.js Rendering Decision

// App Router — per-page rendering strategy
// Static (SSG) — data gak pernah berubah
export const dynamic = "force-static"
 
// Dynamic (SSR) — data per request
export const dynamic = "force-dynamic"
 
// ISR — revalidate setiap N detik
export const revalidate = 3600 // 1 jam
 
// Streaming SSR — progressive rendering
export const dynamic = "auto"
export const experimental = { streaming: true }

3.3 React Server Components (RSC)

// Server Component — zero client JS, direct DB access
async function ProductList() {
  const products = await db.query("SELECT * FROM products")
  return (
    <div>
      {products.map((p) => (
        <ProductCard key={p.id} product={p} />
      ))}
    </div>
  )
}
 
// Client Component — interactivity, hooks
;("use client")
function AddToCart({ productId }: { productId: string }) {
  const [count, setCount] = useState(0)
  return <button onClick={() => setCount((c) => c + 1)}>Add ({count})</button>
}
 
// Mix RSC + Client Component
async function ProductPage({ params }: { params: { id: string } }) {
  const product = await fetchProduct(params.id)
  return (
    <div>
      <ProductInfo product={product} /> {/* Server Component */}
      <ClientWrapper>
        {" "}
        {/* Wrapper client */}
        <ProductReviews productId={params.id} />
        <AddToCart productId={params.id} /> {/* Client Component */}
      </ClientWrapper>
    </div>
  )
}

4. Performance — Bundle, Core Web Vitals, Virtualisasi

4.1 Core Web Vitals

MetricTargetCara Capai
LCP (Loading)< 2.5sOptimize images, preload fonts, minimize render-blocking
FID/INP (Interactivity)< 100ms/200msCode splitting, lazy hydration, debounce handlers
CLS (Visual Stability)< 0.1Set image/video dimensions, avoid layout shift from dynamic content

4.2 Bundle Optimization

// Dynamic import — code splitting
const HeavyChart = dynamic(() => import('./HeavyChart'), {
  loading: () => <ChartSkeleton />,
  ssr: false,  // client-only
});
 
// Route-based splitting (Next.js automatic)
// pages/dashboard.tsx → dashboard.[hash].js
// pages/settings.tsx → settings.[hash].js
 
// Tree shaking — import specifik, bukan seluruh library
// ❌ import { Button } from 'antd';  // import seluruh antd
// ✅ import Button from 'antd/es/button';  // import specifik

4.3 Virtualisasi untuk Long List

// react-window untuk 10,000+ items
import { FixedSizeList } from "react-window"
 
function VirtualList({ items }: { items: Item[] }) {
  return (
    <FixedSizeList height={600} itemCount={items.length} itemSize={50} outerRef={listRef}>
      {({ index, style }) => <div style={style}>{items[index].name}</div>}
    </FixedSizeList>
  )
}

🔗 Koneksi ke Catatan Lain

CatatanKoneksi
software-engineeringPrinsip software umum untuk frontend
clean-code-robert-martinCode quality dan refactoring
web-securityXSS, CSP, CSRF prevention
api-security-deep-diveFrontend-backend security boundary
cicd-guideCI/CD pipeline untuk FE
http-protocol-deepdiveHTTP caching, headers

✅ Checklist

  • Paham perbedaan CSR, SSR, SSG, ISR, RSC
  • Bisa milih state management tool yang tepat
  • Paham component composition patterns
  • Bisa optimasi Core Web Vitals
  • Paham Next.js App Router vs Pages Router
  • Bisa setup testing (Jest + RTL + Playwright)
  • Paham CSS architecture (Module, Tailwind, CSS-in-JS)

Roadmap Belajar

HARI 1: Component Architecture
  - Baca catatan ini sampai selesai
  - Audit component di project Next.js lo — mana yang perlu refactor
  - Implementasi compound component pattern

HARI 2: Rendering Strategy
  - Audit halaman di project: mana yang butuh SSR, SSG, ISR
  - Testing: performance diff antara CSR dan SSR

HARI 3: State Management
  - Migrasi satu page dari Context ke Zustand
  - Setup TanStack Query untuk server state

HARI 4: Performance
  - Lighthouse audit project lo
  - Optimasi LCP/CLS/INP

HARI 5: Testing
  - Setup Jest + RTL untuk component test
  - Setup Playwright untuk E2E critical path

Bottom Line

Frontend engineering bukan cuma “bikin komponen React”. Kenalan dengan rendering strategy, state management, dan performance optimization bakal nentuin apakah aplikasi lo terasa cepat atau nge-lag di production. Next.js App Router dengan RSC adalah default yang baik untuk 2026 — tapi paham fundamental rendering patterns tetap penting biar gak salah pilih strategy untuk use case yang beda.

Lanjutan

Catatan ini fokus ke React/Next.js. Ekosistem frontend juga mencakup Vue/Nuxt, Svelte/SvelteKit, dan Solid.js — topik untuk catatan terpisah. Juga terkait: software-engineering (prinsip umum), web-security (frontend security).