Mengenal Komponen di React JS: Functional vs Class

Jika kamu baru mulai belajar React JS, kamu pasti akan sering mendengar istilah komponen. Komponen adalah bagian paling dasar dan penting dalam membangun antarmuka pengguna (UI) di React. Bisa dibilang, seluruh aplikasi React adalah kumpulan dari banyak komponen yang bekerja bersama-sama.

Nah, di React sendiri ada dua cara utama untuk membuat komponen: Functional Component dan Class Component. Keduanya bisa digunakan untuk tujuan yang sama, tapi punya gaya penulisan, fitur, dan cara kerja yang sedikit berbeda.

Pada awalnya, Class Component dianggap lebih powerful karena bisa mengelola state dan menggunakan lifecycle methods. Tapi sejak diperkenalkannya React Hooks pada versi 16.8, Functional Component pun jadi sangat fleksibel—bahkan kini lebih direkomendasikan dalam banyak kasus.

Di artikel ini, kita akan:

  • Mengenal kedua jenis komponen dengan penjelasan dan contoh kode.
  • Membahas perbedaan utama antara Functional dan Class Component.
  • Menjelaskan kesalahan umum yang sering terjadi saat menggunakannya.
  • Memberikan beberapa best practice agar kamu bisa menulis komponen React dengan lebih baik.

Jadi, kalau kamu masih bingung: “Harus pakai yang mana, Functional atau Class?”, tenang… kita bahas satu per satu dengan contoh nyata.

Persiapan Proyek dan Cara Instalasi

Sebelum kita mulai ngulik komponen di React, tentu kita perlu siapkan dulu proyek React nya, biar bisa langsung praktek dan nggak cuma teori doang.

Syarat Awal

Pastikan kamu udah install Node.js di komputer kamu, minimal versi 14 ya. Buat ngecek, buka terminal atau command prompt terus ketik:

node -v
npm -v

Ini versi yg saya gunakan:

Terminal Windows
Terminal Windows

Kalau keluar versinya berarti udah oke, kalo belum, kamu bisa download Node.js dari situs resmi nodejs.org.

Instalasi React dengan Next.js

Nah, buat mulai proyek React, kita bakal pake Next.js. Next.js ini keren banget karena selain React biasa, dia juga punya fitur kayak routing otomatis dan server-side rendering yang bikin performa aplikasi makin ngebut.

Buka terminal terus ketik perintah ini buat bikin proyek baru:

npx create-next-app@latest bwa-react

Jika ada konfirmasi seperti ini tekan Enter di keyboard

Terminal: Install Next.js
Terminal: Install Next.js
  • √ Would you like to use TypeScript? ... Pilih Yes
  • √ Would you like to use ESLint? ... Pilih Yes
  • √ Would you like to use Tailwind CSS? ... Pilh Yes
  • √ Would you like your code inside a src/ directory? ... Pilih Yes
  • √ Would you like to use App Router? (recommended) ... Pilih Yes
  • √ Would you like to use Turbopack for next dev? ... Pilih Yes
  • √ Would you like to customize the import alias (@/* by default)? ... Pilih No
Terminal: Install Next.js
Terminal: Install Next.js

Jika proses intallasi sudah selesai, masuk ke folder proyeknya:

cd bwa-react

Terus jalankan development server dengan perintah:

npm run dev
Terminal: Menjalankan Next.js
Terminal: Menjalankan Next.js

Biasanya bakal keluar alamat http://localhost:3000 di terminal. Kamu buka alamat itu di browser, dan… voila! Kamu udah punya proyek React dengan Next.js siap pakai.

Tampilan awal Next.js
Tampilan awal Next.js

Kalau kamu pake bun, tinggal ganti aja npm jadi bun di perintah-perintah tadi.

Mengenal Komponen di React

Oke, sekarang saatnya masuk ke inti dari pembahasan kita: komponen. Jadi, di React, semua hal yang tampil di layar itu sebenernya dibangun dari komponen. Mulai dari tombol, teks, gambar, sampai halaman penuh semuanya komponen.

Apa itu Komponen?

Komponen itu bisa dibilang kayak "blok bangunan" dari UI aplikasi kita. Dia bisa dipake ulang, bisa dikasih data, dan bisa saling terhubung satu sama lain. Ibaratnya kayak LEGO, kamu gabungin banyak potongan kecil jadi satu bentuk utuh.

Ada dua jenis utama komponen di React:

  • Functional Component (alias komponen fungsi)
  • Class Component (alias komponen kelas)

Keduanya bisa dipake buat hal yang sama, tapi punya gaya nulis yang beda dan cara kerja yang sedikit… ya beda dikit lah.

Functional Component

Functional Component ditulis sebagai fungsi JavaScript biasa. Sejak adanya Hooks, Functional Component bisa ngelakuin hampir semua hal yang dulu cuma bisa di Class Component.

Contoh sederhana:

// components/HelloFunctional.tsx

type HelloProps = {
  name: string;
};

function HelloFunctional(props: HelloProps) {
  return <h1>Halo, {props.name}!</h1>;
}

export default HelloFunctional;

Atau bisa juga pake arrow function (lebih modern):

// components/HelloFunctionalArrow.tsx

type HelloProps = {
  name: string;
};

const HelloFunctional: React.FC<HelloProps> = ({ name }) => {
  return <h1>Halo, {name}!</h1>;
};

export default HelloFunctional;

Class Component

Dulu, sebelum Hooks muncul, kalo kamu mau pake state atau lifecycle method, kamu harus pake Class Component.

Contoh:

// components/HelloClass.tsx

import { Component } from 'react';

type HelloProps = {
  name: string;
};

class HelloClass extends Component<HelloProps> {
  render() {
    return <h1>Halo, {this.props.name}!</h1>;
  }
}

export default HelloClass;

Tapi sekarang, Class Component udah jarang dipake di proyek baru. Bukan berarti dilarang ya, cuma tren-nya udah beralih ke Functional Component.

Perbandingan Singkat

FiturFunctional ComponentClass Component
PenulisanLebih ringkas & simpleLebih verbose
State & lifecyclePakai HooksPakai this.state & this.setState
Kode reuseLebih mudah dengan HooksLebih terbatas
Popularitas sekarangSangat direkomendasikanMasih dipakai di proyek lama
Tabel perbandingan functional component dan class component

Masih bingung pilih yang mana? Tenang, kita bakal bahas lebih lanjut soal perbedaan dan kapan sebaiknya pake yang mana.

Perbedaan Utama Functional vs Class Component

Meski sama-sama bisa dipake buat bikin tampilan, ada beberapa perbedaan penting antara Functional Component dan Class Component. Biar nggak bingung, kita bahas satu-satu ya.

Penulisan (Sintaks)

Functional Component itu lebih ringkas. Cukup nulis fungsi, langsung return elemen JSX.

// Functional
const Hello = () => <h1>Hello, World!</h1>;

Bandingin sama Class Component:

// Class
class Hello extends React.Component {
  render() {
    return <h1>Hello, World!</h1>;
  }
}

Liat kan? Class Component butuh lebih banyak baris buat hal yang sebenernya sama aja.

Mengelola State

Functional Component sekarang udah bisa pake Hooks buat ngatur state.

import { useState } from 'react';

const Counter = () => {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Jumlah: {count}</p>
      <button onClick={() => setCount(count + 1)}>Tambah</button>
    </div>
  );
};

export default Counter;

Dulu (dan masih bisa), kalo mau pake state harus pake Class Component:

// components/CounterClass.tsx
import { Component } from 'react';

type CounterState = {
  count: number;
};

class CounterClass extends Component<{}, CounterState> {
  constructor(props: {}) {
    super(props);
    this.state = { count: 0 };
  }

  handleTambah = () => {
    this.setState((prev) => ({ count: prev.count + 1 }));
  };

  render() {
    return (
      <div>
        <p>Jumlah: {this.state.count}</p>
        <button onClick={this.handleTambah}>Tambah</button>
      </div>
    );
  }
}

export default CounterClass;

Agak panjang ya 😅

Lifecycle

Class Component punya lifecycle methods kayak componentDidMount, componentDidUpdate, dll.

componentDidMount() {
  console.log('Component muncul ke layar!');
}

Tapi di Functional Component, kamu bisa ngelakuin hal yang sama pake useEffect:

import { useEffect } from 'react';

useEffect(() => {
  console.log('Komponen dimuat ke layar!');
}, []);

Sama fungsinya, tapi jauh lebih simpel dan fleksibel.

Konteks “this”

Di Class Component, kamu sering harus berurusan sama this, dan itu bisa bikin pusing.

this.setState(...);
this.props.nama;

Sementara di Functional Component, semuanya lebih clean—nggak perlu mikir soal this.

Performance?

Secara performa, dua-duanya hampir sama di kebanyakan kasus. Tapi karena Functional Component lebih ringan dan mudah dioptimasi (terutama dengan React 18 dan concurrent mode), biasanya jadi pilihan utama buat proyek baru.


Singkatnya:

  • Proyek baru? Functional Component + Hooks adalah best choice.
  • Ngurusin proyek lama? Kadang masih ketemu Class Component, dan itu gapapa.
  • Mau belajar dua-duanya? Bagus! Jadi kamu ngerti semua ekosistem React.

Contoh Kode Lengkap Functional vs Class Component

Studi Kasus:

Kita mau bikin komponen UserProfile yang:

  • Nampilin nama & email pengguna
  • Bisa toggle status login (on/off)

Functional Component (dengan Hooks)

// components/UserProfileFunctional.tsx

import { Component } from "react";

type UserProfileProps = {
  name: string;
  email: string;
};

type UserProfileState = {
  loggedIn: boolean;
};

class UserProfileClass extends Component<UserProfileProps, UserProfileState> {
  constructor(props: UserProfileProps) {
    super(props);
    this.state = {
      loggedIn: false,
    };
  }

  toggleLogin = () => {
    this.setState((prev) => ({
      loggedIn: !prev.loggedIn,
    }));
  };

  render() {
    const { name, email } = this.props;
    const { loggedIn } = this.state;
    const statusClass = `rounded-full h-10 w-10 ${
      loggedIn ? "bg-green-500" : "bg-red-500"
    }`;
    const btnClass = `mt-4 px-4 py-1.5 cursor-pointer rounded-full text-white font-bold ${
      loggedIn ? "bg-red-300" : "bg-blue-400"
    }`;

    return (
      <div className="flex flex-col gap-2 border-2 p-4 rounded-2xl">
        <div className="flex gap-2.5 items-center">
          <div className={statusClass}></div>
          <div className="flex flex-col">
            <h2 className="font-bold">{name}</h2>
            <p className="opacity-80 text-[14px]">{email}</p>
          </div>
        </div>
        <button onClick={this.toggleLogin} className={btnClass}>
          {loggedIn ? "Logout" : "Login"}
        </button>
      </div>
    );
  }
}

export default UserProfileClass;

🟢 Kelebihan:

  • Ringkas dan gampang dibaca
  • Gunain useState buat handle login
  • Nggak repot sama this

Class Component (dengan state & event)

// components/UserProfileClass.tsx

import { Component } from "react";

type UserProfileProps = {
  name: string;
  email: string;
};

type UserProfileState = {
  loggedIn: boolean;
};

class UserProfileClass extends Component<UserProfileProps, UserProfileState> {
  constructor(props: UserProfileProps) {
    super(props);
    this.state = {
      loggedIn: false,
    };
  }

  toggleLogin = () => {
    this.setState((prev) => ({
      loggedIn: !prev.loggedIn,
    }));
  };

  render() {
    const { name, email } = this.props;
    const { loggedIn } = this.state;
    const statusClass = `rounded-full h-10 w-10 ${
      loggedIn ? "bg-green-500" : "bg-red-500"
    }`;
    const btnClass = `mt-4 px-4 py-1.5 cursor-pointer rounded-full text-white font-bold ${
      loggedIn ? "bg-red-300" : "bg-blue-400"
    }`;

    return (
      <div className="flex flex-col gap-2 border-2 p-4 rounded-2xl">
        <div className="flex gap-2.5 items-center">
          <div className={statusClass}></div>
          <div className="flex flex-col">
            <h2 className="font-bold">{name}</h2>
            <p className="opacity-80 text-[14px]">{email}</p>
          </div>
        </div>
        <button onClick={this.toggleLogin} className={btnClass}>
          {loggedIn ? "Logout" : "Login"}
        </button>
      </div>
    );
  }
}

export default UserProfileClass;

🔴 Kekurangan:

  • Lebih verbose
  • Perlu constructor & this buat handle event & state

Jika kalian mendapatkan error seperti berikut, itu karena defaultnya di Next.js semua komponen itu menggunakan server comonent, dan useState itu hanya bisa digunakan di client component. Kalian bisa belajar tentang server component dan client component pada postingan BuildWithAngga tentang Tutorial Next.js 15 Belajar Server dan Client Component Projek Web Booking Hotel.

Next.js build error
Next.js build error

Untuk mengatasi ini, kita tinggal tambahkan "use client" pada baris pertama kode, jadinya seperti ini:

"use client";

import { Component } from "react";

type UserProfileProps = {
  name: string;
  email: string;
};

type UserProfileState = {
  loggedIn: boolean;
};

class UserProfileClass extends Component<UserProfileProps, UserProfileState> {
  constructor(props: UserProfileProps) {
    super(props);
    this.state = {
      loggedIn: false,
    };
  }

  toggleLogin = () => {
    this.setState((prev) => ({
      loggedIn: !prev.loggedIn,
    }));
  };

  render() {
    const { name, email } = this.props;
    const { loggedIn } = this.state;
    const statusClass = `rounded-full h-10 w-10 ${
      loggedIn ? "bg-green-500" : "bg-red-500"
    }`;
    const btnClass = `mt-4 px-4 py-1.5 cursor-pointer rounded-full text-white font-bold ${
      loggedIn ? "bg-red-300" : "bg-blue-400"
    }`;

    return (
      <div className="flex flex-col gap-2 border-2 p-4 rounded-2xl">
        <div className="flex gap-2.5 items-center">
          <div className={statusClass}></div>
          <div className="flex flex-col">
            <h2 className="font-bold">{name}</h2>
            <p className="opacity-80 text-[14px]">{email}</p>
          </div>
        </div>
        <button onClick={this.toggleLogin} className={btnClass}>
          {loggedIn ? "Logout" : "Login"}
        </button>
      </div>
    );
  }
}

export default UserProfileClass;

Tambahkan juga "use client" pada UserProfileClass.tsx.

Buka page.tsx lalu ubah jadi seperti ini:

import UserProfileClass from "@/components/UserProfileClass";
import UserProfileFunctional from "@/components/UserProfileFunctional";

export default function Home() {
  return (
    <div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
      <main className="flex flex-col gap-[32px] row-start-2 items-center sm:items-start">
        <h3 className="text-2xl font-bold">Functional Component:</h3>
        <UserProfileFunctional
          name="Taufan Fatahillah"
          email="[email protected]"
        />
        <h3 className="text-2xl font-bold">Class Component:</h3>
        <UserProfileClass name="Jonh Doe" email="[email protected]" />
      </main>
    </div>
  );
}

Hasilnya akan seperti ini:

Local Result
Local Result

Catatan Tambahan

  • Untuk proyek baru, disarankan pake Functional Component + Hooks
  • Tapi belajar Class Component tetep penting kalau kamu ketemu kode lama (legacy code)

Kesalahan Umum yang Harus Dihindari

Walaupun React keliatannya simpel, tapi banyak juga jebakan yang sering bikin frustrasi. Nih, beberapa kesalahan umum yang sering kejadian:

Lupa Typing Props

Ini klasik banget. Di TypeScript, semua props harus didefinisiin typenya. Kalau nggak, kamu bakal kehilangan auto-complete dan bisa bikin bug susah dilacak.

// ❌ Salah (nggak ada type)
function Greet(props) {
  return <p>Hi, {props.name}</p>;
}
// ✅ Benar
type GreetProps = {
  name: string;
};

function Greet({ name }: GreetProps) {
  return <p>Hi, {name}</p>;
}

Gunain any terus-terusan

Pakai any itu kayak ngilangin fitur utama TypeScript. Kalau sering pakai any, sama aja kayak balik ke JavaScript biasa 😅

// ❌ Salah
const handleClick = (e: any) => {
  console.log(e.target.value);
};
// ✅ Benar
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
  console.log(e.currentTarget.value);
};

State di Functional Component Tanpa Tipe

React bisa nebak tipenya sih, tapi kalau datanya kompleks, sebaiknya tetap definisiin tipe-nya.

// ❌ Salah
const [user, setUser] = useState(null);
// ✅ Benar
type User = {
  name: string;
  age: number;
};

const [user, setUser] = useState<User | null>(null);

Mengakses this di Functional Component

Kadang yang baru pindah dari Class suka iseng nulis this.props di Functional 🤦

// ❌ Salah
const MyComponent = () => {
  console.log(this.props); // ini pasti error
};

Import React tapi nggak dipakai

Sejak React 17, kamu nggak wajib import React di file yang pakai JSX. Tapi kadang orang masih nulis ini padahal gak perlu.

// ❌ Nggak perlu kalau nggak pakai React secara eksplisit
import React from 'react';

Best Practices dalam Menulis Komponen React + TypeScript

Nah, biar kode kamu clean, maintainable, dan scalable, coba terapin beberapa best practice berikut:

Pisahin Tipe Props ke File Sendiri (kalau kompleks)

Kalau props-nya banyak atau dipakai di banyak komponen, lebih baik dipisah ke file types.ts.

// types/User.ts
export type User = {
  name: string;
  email: string;
};
// components/UserCard.tsx
import { User } from '@/types/User';

const UserCard = ({ name, email }: User) => {
  return <div>{name} - {email}</div>;
};

Gunain Destructuring Props

Lebih rapi dan enak dibaca dibanding props.name, props.email, dst.

// ✅ Lebih clean
const Profile = ({ name, age }: { name: string; age: number }) => {
  return <p>{name} - {age}</p>;
};

Selalu Type State dengan Jelas

Daripada ngandelin inferensi TypeScript, lebih baik kamu tegasin typenya, apalagi kalau datanya nullable atau array.

const [todos, setTodos] = useState<TodoItem[]>([]);

Gunain React.FC untuk Komponen Simpel

Kalau komponen kamu cuma pake props bawaan, React.FC bisa ngebantu banyak (auto children, auto typing props):

type AlertProps = {
  message: string;
};

const Alert: React.FC<AlertProps> = ({ message, children }) => {
  return <div>{message} {children}</div>;
};

Break Down Komponen Jadi Kecil-kecil

Jangan bikin satu komponen isinya ribuan baris. Pisah jadi komponen kecil yang reusable.

// components/Post.tsx
const Post = ({ title, author }: { title: string; author: string }) => (
  <article>
    <h2>{title}</h2>
    <small>by {author}</small>
  </article>
);

Gunakan ESLint + Prettier + TypeScript Strict Mode

Biar kode kamu tetap bersih, konsisten, dan minim bug dari awal.


ESLintLinting Code JavaScript/TypeScript

ESLint itu semacam "pengawas" kode kita. Dia bantu nyari dan ngasih warning/error kalau ada potensi bug atau style yang nggak konsisten. Contoh:

const a = 5
console.log(a)

Tanpa ESLint:

  • Kode di atas dianggap sah-sah aja.

Dengan ESLint:

  • Bisa dikasih warning karena console.log, titik koma, atau penamaan variabel nggak sesuai aturan.

PrettierCode Formatter Otomatis

Prettier fokus ke formatting, bukan logic. Dia bantu rapihin kode secara otomatis. Misalnya:

const hello =   (name:string)=>{return "Hi "+name}

Setelah Prettier:

const hello = (name: string) => {
  return "Hi " + name;
};

Auto rapi, konsisten, dan bikin kode enak dibaca tim 😎


TypeScript Strict ModeType Safety Ketat

strict: true di tsconfig.json artinya kamu bilang ke TypeScript:

"Bro, tolong pastiin semua variable, return type, props, dsb harus jelas dan aman ya!”

Contoh:

// Tanpa strict mode
function greet(name) {
  return 'Hello ' + name;
}
// Dengan strict mode
function greet(name: string): string {
  return 'Hello ' + name;
}

Hasilnya: Lebih sedikit bug, lebih pede deploy 🚀


Next.js Include ESLint by Default

Kalau kamu bikin proyek Next.js baru (npx create-next-app), Next.js bakal langsung nanya:

"Mau aktifin ESLint?"

Dan kalau kamu klik "Yes", dia bakal:

  • Auto install ESLint
  • Tambah file .eslintrc.json
  • Konfig yang cocok buat Next.js

Kamu tinggal pakai aja tanpa setup ribet!


Bonus: Gabungin Semuanya

Untuk workflow terbaik, kamu bisa gabungin keempatnya:

  • ✅ ESLint → cek kode logic & style
  • ✨ Prettier → rapihin format otomatis
  • 🔐 TypeScript Strict → jaga keamanan dan kejelasan data
  • ⚡ Next.js → tinggal pake, udah include tools-nya

Perbandingan Singkat Functional vs Class Component (Tabel)

AspekFunctional ComponentClass Component
SintaksFungsi biasa atau arrow functionMenggunakan class dan extends React.Component
StateGunakan useStateGunakan this.state dan this.setState
Lifecycle MethodGunakan useEffectGunakan componentDidMount, componentDidUpdate, dll
Hooks Support✅ Ya❌ Tidak
Binding this❌ Tidak perlu✅ Perlu
Kode lebih ringkas✅ Umumnya lebih ringkas❌ Lebih verbose
Digunakan di proyek baru✅ Sangat disarankan❌ Jarang, kecuali legacy
Dukungan TypeScript✅ Sangat baik✅ Tapi butuh lebih banyak kode
Tabel perbandingan singkat

Kapan Sebaiknya Pakai Functional vs Class?

Gunakan Functional Component jika:

  • Kamu baru belajar React (lebih simpel dan modern)
  • Proyek baru menggunakan React 16.8+
  • Ingin menggunakan Hooks seperti useState, useEffect, useContext, dll
  • Ingin kode lebih singkat dan mudah dibaca
  • Ingin mengikuti best practice terbaru

Gunakan Class Component jika:

  • Kamu sedang maintenance proyek lama
  • Proyek menggunakan React versi lama (di bawah 16.8)
  • Komponen sudah sangat besar dan susah untuk diubah total ke function

Tapi secara umum, Functional Component adalah standar modern React. Bahkan tim React sendiri merekomendasikan penggunaan fungsi ketimbang class.


Penutup

Di artikel ini, kita udah bahas lumayan lengkap tentang:

  • Apa itu Functional dan Class Component di React
  • Cara setup proyek Next.js + TypeScript
  • Contoh kode untuk dua jenis komponen
  • Kesalahan umum yang sering kejadian
  • Best practices biar kode lebih rapi dan scalable
  • 📌 Perbandingan dan kapan sebaiknya digunakan

🚀 Rekomendasi Selanjutnya:

  1. Tutorial Next JS 15 Belajar Server dan Client Components Projek Web Booking Hotel
  2. 10 Hal Perlu Dipelajari Pemula Framework Next.js 15
  3. Tutorial Next JS Pemula Mengenal Pentingnya Webpack
  4. Cara Deploy Website Statis ke Vercel lewat GitHub (Lengkap + Contoh)