Higher-Order Components — React

Bayangin kamu nemu codebase legacy: ada yang dibungkus jadi withAuth(withLoading(withTheme(UserList))) — empat lapis HOC sebelum komponen aslinya kerja. Apa itu

Bayangin kamu nemu codebase legacy: ada <UserList> yang dibungkus jadi withAuth(withLoading(withTheme(UserList))) — empat lapis HOC sebelum komponen aslinya kerja. Apa itu? Higher-Order Component (HOC) adalah pattern reuse logic di React era pre-hooks (2014-2018): function yang nerima component, return component baru yang diperkaya dengan extra functionality. Mirip decorator di Python atau middleware di Express. Sekarang? Hooks udah ngantiin HOC di kebanyakan kasus — lebih simple, lebih type-friendly. Tapi HOC tetep wajib dipelajari karena banyak library lama (Redux connect, React Router withRouter, MobX observer) masih pakai pola ini.

⚠️ Pola lama, masih relevan. HOC bukan deprecated, cuma jarang jadi pilihan pertama di kode baru. Skill ini WAJIB kalau kamu kerja di project React 2-5 tahun yang lalu — banyak codebase company di Indonesia masih pake. Plus paham HOC = paham fundamental composition pattern.

Anatomi HOC

function withLoading(WrappedComponent) {
  return function(props) {
    if (props.isLoading) {
      return <div>Loading...</div>
    }
    return <WrappedComponent {...props} />
  }
}

// Pemakaian
const UserListWithLoading = withLoading(UserList)
// <UserListWithLoading isLoading={true} users={[...]} />

withLoading = HOC. Terima component, return component baru yang punya behavior tambahan (cek isLoading sebelum render).

Pattern Umum HOC

// withAuth — cek user sebelum render
function withAuth(Component) {
  return function(props) {
    const { user } = useContext(AuthContext)
    if (!user) return <LoginPage />
    return <Component {...props} user={user} />
  }
}

// withErrorBoundary — wrap dengan error boundary
function withErrorBoundary(Component, FallbackUI) {
  return function(props) {
    return (
      <ErrorBoundary fallback={FallbackUI}>
        <Component {...props} />
      </ErrorBoundary>
    )
  }
}

// withLogger — log lifecycle
function withLogger(Component, name) {
  return function(props) {
    useEffect(() => {
      console.log(`${name} mounted`)
      return () => console.log(`${name} unmounted`)
    }, [])
    return <Component {...props} />
  }
}

Compose Multiple HOC

const EnhancedComponent = withAuth(withLoading(withTheme(UserList)))

// Atau pakai compose helper:
import { compose } from "lodash/fp"

const enhance = compose(withAuth, withLoading, withTheme)
const EnhancedComponent = enhance(UserList)

HOC vs Custom Hook — Side by Side

// HOC
function withMousePosition(Component) {
  return function(props) {
    const [pos, setPos] = useState({ x: 0, y: 0 })
    useEffect(() => {
      const handler = (e) => setPos({ x: e.clientX, y: e.clientY })
      window.addEventListener("mousemove", handler)
      return () => window.removeEventListener("mousemove", handler)
    }, [])
    return <Component {...props} mousePosition={pos} />
  }
}
const Tracker = withMousePosition(MyComponent)

// CUSTOM HOOK — modern, simple
function useMousePosition() {
  const [pos, setPos] = useState({ x: 0, y: 0 })
  useEffect(() => {
    const handler = (e) => setPos({ x: e.clientX, y: e.clientY })
    window.addEventListener("mousemove", handler)
    return () => window.removeEventListener("mousemove", handler)
  }, [])
  return pos
}

function Tracker() {
  const pos = useMousePosition()  // ← langsung pakai
  return <div>x: {pos.x}</div>
}

Hook lebih simple, no wrapping, type signature lebih jelas.

Konvensi HOC

🎭 Analogi sehari-hari

HOC itu kayak bungkus kado berlapis. Komponen aslinya = mainan favorit anak. withLoading = lapis kertas bungkus pertama (handle "tunggu, lagi siap-siap"). withAuth = lapis kedua (cek "kamu udah ulang tahun belum"). withTheme = lapis ketiga (warna pita sesuai mood). User akhirnya buka bungkus kado satu-satu, mainan keluar di akhir. Custom hook lebih kayak alat masak yang dipake langsung: gak perlu bungkus tambahan, kasih ke chef (component) sebagai tools yang bisa dipake. HOC = pattern lama yang masih jalan, hooks = pattern baru yang lebih efisien.

⚠️ Jebakan yang sering ditemui

🎯 Pakai HOC atau Custom Hook?

  • Project baru, butuh reuse logic → custom hook ✓ (default modern)
  • Project legacy yang udah pakai HOC → tetap HOC (consistency)
  • Wrap component dengan render UI tambahan (loading screen, auth wall) → HOC bisa lebih natural
  • Inject props ke component → HOC ATAU hook + render prop
  • Cross-cutting concern (logging, analytics) → HOC lebih cocok untuk inject di tingkat component
  • Library wrapper (Redux connect, React Query withQueries) → masih HOC (existing API)

Aturan modern: hooks first. HOC cuma pas hook gak fit (component-level wrapping, conditional render gating).

TL;DR: HOC = function yang nerima component, return component baru dengan extra functionality. Pattern lama (pre-hooks) untuk reuse logic. Convention: nama mulai with, forward props ({...props}), jangan mutate. Modern alternative: Custom Hooks lebih simple + type-friendly. HOC tetep relevan untuk: codebase legacy, library wrapper, component-level wrapping (auth, error boundary). Skill wajib pas maintain project React 2-5 tahun lalu.

Yang akan kamu pelajari