Cara Membuat Component di React JS

jujur, dulu saya pikir React itu ribet, tapi begitu paham konsep component, semuanya jadi klik. kalau sebelumnya saya bikin halaman panjang satu file, sekarang tiap bagian kecil saya pecah jadi component yang bisa dipakai ulang. di artikel ini kalian akan bikin component pertama, main props, dan nyusun komposisi yang menurut saya paling enak dibaca. kalau JavaScript dasarnya masih goyang, mampir dulu ke array methods map filter reduce dan localStorage di JavaScript, biar tidak kaget pas ketemu map dan useState.
1. component itu apa sih
component itu blok UI yang bisa dipakai ulang, tulisnya sebagai function yang return JSX. analoginya simpel, kayak function biasa, nerima input berupa props, ngembaliin output berupa UI. bisa di-nesting, bisa dipakai sepuluh kali dengan data beda.
di React ada dua jenis:
- functional component, function biasa, ini standar modern sejak React 16.8 plus hooks
- class component, pakai
class extends React.Component, sekarang jarang saya pakai, cuma ketemu di library lama
menurut saya, pakai functional saja, sudah cukup untuk 99% kasus.
2. bikin functional component paling simpel
// components/Greeting.jsx
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}
export default Greeting;
sedikit catatan dari saya:
function Greeting({ name }), pakai destructuring biar tidakprops.nameterusreturn <h1>Hello, {name}!</h1>, kurung kurawal di dalam JSX itu buat interpolasiexport default Greeting, biar bisa di-import di file lain
3. cara pakai component
// App.jsx
import Greeting from './components/Greeting';
function App() {
return (
<div>
<Greeting name="Andi" />
<Greeting name="Budi" />
</div>
);
}
kalau di aplikasi saya, satu component sering saya pakai tiga empat kali dengan props beda, misal Greeting di atas. tidak perlu copy paste h1 dua kali, cukup panggil component-nya.
4. JSX yang perlu kalian hafal
JSX itu extension yang bikin kalian bisa nulis kayak HTML di dalam JavaScript:
function UserCard() {
const name = "Andi";
const age = 25;
const isActive = true;
return (
<div className="card">
<h2>{name}</h2>
<p>Umur: {age}</p>
<p>Status: {isActive ? "Aktif" : "Non-aktif"}</p>
</div>
);
}
beberapa aturan yang sering bikin saya kepleset di awal:
- harus return satu root, kalau mau dua element pakai Fragment
<>...</> - atribut pakai camelCase, jadi
classjadi className,forjadi htmlFor,onclickjadi onClick - interpolasi pakai
{...}, di dalamnya boleh variable atau ternary - string literal tetap
name="Andi"pakai kutip biasa
5. props yang agak lengkap
props itu input, mirip parameter function, sifatnya read-only ya:
function Button({
children, // konten di antara tag
variant = "primary", // default value
size = "medium",
disabled = false,
onClick,
className = "",
...rest // sisa props
}) {
return (
<button
className={`btn btn-${variant} btn-${size} ${className}`}
disabled={disabled}
onClick={onClick}
{...rest}
>
{children}
</button>
);
}
// Penggunaan
<Button variant="success" size="large" onClick={handleClick}>
Simpan Data
</Button>
yang saya pelajari dari bikin Button kayak gini:
childrenitu slot untuk apa pun di antara<Button>...</Button>- kasih default value biar pemanggil tidak wajib kirim semua props
...restberguna buatid,data-*, atauaria-*tanpa harus didefinisikan satu-satu
6. pattern children buat composition
// Card.jsx
function Card({ title, children, footer }) {
return (
<div className="card">
{title && <div className="card-header"><h3>{title}</h3></div>}
<div className="card-body">{children}</div>
{footer && <div className="card-footer">{footer}</div>}
</div>
);
}
// Penggunaan
<Card
title="Profil Pengguna"
footer={<button>Edit</button>}
>
<p>Nama: Andi</p>
<p>Email: andi@example.com</p>
</Card>
kalau pakai children, Card tidak perlu tahu isinya apa. mau isi paragraf, form, bahkan button, tinggal selipkan. lebih fleksibel daripada bikin props bodyText dan footerText satu-satu.
7. render kondisional, jangan overthinking
saya biasanya pakai tiga cara ini saja:
function UserGreeting({ user, isLoading, error }) {
// 1. early return untuk loading/error
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
if (!user) return <p>Silakan login</p>;
// 2. ternary untuk if-else inline
return (
<div>
{user.isVerified ? (
<span className="badge">✓ Verified</span>
) : (
<span className="badge gray">Unverified</span>
)}
{/* 3. && untuk render kalau true */}
{user.notifications.length > 0 && (
<span>Kamu punya {user.notifications.length} notifikasi</span>
)}
</div>
);
}
catatan kecil yang pernah bikin saya bug, kalau pakai && jangan count && <p>, karena kalau count 0, React akan render angka 0. pakai count > 0 && <p> lebih aman.
8. list dan key, jangan asal index
function TodoList({ todos }) {
return (
<ul>
{todos.map(todo => (
<li key={todo.id} className={todo.completed ? "done" : ""}>
{todo.text}
</li>
))}
</ul>
);
}
// Penggunaan
<TodoList todos={[
{ id: 1, text: "Belajar React", completed: true },
{ id: 2, text: "Bikin project", completed: false }
]} />
aturan yang selalu saya pegang buat key:
- wajib ada, kalau tidak React ngasih warning
- harus unik antar sibling, biasanya pakai
iddari database - jangan pakai index array kalau urutan bisa berubah, nanti animasi dan state jadi aneh
- jangan pakai
Math.random(), tiap render ganti dan bikin re-render semua
9. state pakai useState
functional component jadi hidup kalau pakai hooks. yang paling sering, useState:
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>+</button>
<button onClick={() => setCount(count - 1)}>-</button>
<button onClick={() => setCount(0)}>Reset</button>
</div>
);
}
sedikit cerita, dulu saya kira setCount itu langsung ubah variable, ternyata dia minta React render ulang. jadi jangan count++ langsung, tapi setCount(count + 1). kalau butuh reset, setCount(0) saja.
10. side effect pakai useEffect
useEffect itu tempat buat fetch data atau subscribe, kalau di component biasa:
import { useState, useEffect } from 'react';
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(true);
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(data => {
setUser(data);
setLoading(false);
});
}, [userId]); // re-run kalau userId berubah
if (loading) return <p>Loading...</p>;
if (!user) return <p>User tidak ditemukan</p>;
return (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
</div>
);
}
tiga variasi yang sering saya pakai:
useEffect(() => {...}), jalan tiap render, jarang saya pakaiuseEffect(() => {...}, []), jalan sekali pas mountuseEffect(() => {...}, [userId]), jalan pas mount dan tiapuserIdganti- jangan lupa return cleanup,
return () => unsubscribe()kalau pakai subscription
11. nyusun component kecil jadi besar
kalau sudah punya Button kecil, kita bisa bikin Modal generik, lalu ConfirmDialog spesifik:
// components/Button.jsx
function Button({ variant = "primary", size = "medium", children, onClick }) {
return (
<button
className={`btn btn-${variant} btn-${size}`}
onClick={onClick}
>
{children}
</button>
);
}
// components/Modal.jsx
function Modal({ isOpen, onClose, title, children }) {
if (!isOpen) return null;
return (
<div className="modal-overlay" onClick={onClose}>
<div className="modal-content" onClick={e => e.stopPropagation()}>
<header>
<h2>{title}</h2>
<Button variant="ghost" size="small" onClick={onClose}>×</Button>
</header>
<div className="modal-body">{children}</div>
</div>
</div>
);
}
// components/ConfirmDialog.jsx
function ConfirmDialog({ isOpen, title, message, onConfirm, onCancel }) {
return (
<Modal isOpen={isOpen} onClose={onCancel} title={title}>
<p>{message}</p>
<div className="dialog-actions">
<Button variant="ghost" onClick={onCancel}>Batal</Button>
<Button variant="danger" onClick={onConfirm}>Hapus</Button>
</div>
</Modal>
);
}
alasannya saya suka composition, Button bisa dipakai di mana saja, Modal tidak tahu isinya, dan ConfirmDialog tinggal kombinasikan dua-duanya. lebih enak di-maintain daripada satu component raksasa 300 baris.
12. struktur folder yang enak di mata
src/
├── components/ # component kecil, reusable
│ ├── Button.jsx
│ ├── Card.jsx
│ └── Modal.jsx
├── features/ # feature-based component
│ ├── auth/
│ │ ├── LoginForm.jsx
│ │ └── RegisterForm.jsx
│ └── todo/
│ ├── TodoList.jsx
│ ├── TodoItem.jsx
│ └── AddTodo.jsx
├── pages/ # component per route
│ ├── Home.jsx
│ ├── About.jsx
│ └── Profile.jsx
├── hooks/ # custom hooks
│ └── useLocalStorage.js
├── utils/ # utility function
│ └── api.js
├── App.jsx
└── main.jsx
kalau bingung, pegang ini dulu:
- components/ buat primitives kayak Button dan Card
- features/ buat yang spesifik per fitur
- pages/ buat route
- tiap folder feature saya biasakan ada
index.jsbiar import rapi
13. setup project pakai Vite
sekarang saya sudah tidak pakai Create React App lagi, sudah deprecated. pakai Vite jauh lebih ngebut:
npm create vite@latest my-app -- --template react
cd my-app
npm install
npm run dev
kalau mau TypeScript langsung:
npm create vite@latest my-app -- --template react-ts
struktur yang dibikin Vite:
my-app/
├── public/
│ └── vite.svg
├── src/
│ ├── assets/
│ │ └── react.svg
│ ├── App.jsx
│ ├── App.css
│ ├── index.css
│ └── main.jsx # entry point
├── index.html
├── package.json
└── vite.config.js
14. butuh banyak element tanpa div
// ❌ Error: JSX harus return satu element
function UserInfo() {
return (
<h1>Andi</h1>
<p>Developer</p>
);
}
// ✅ Pakai div wrapper
function UserInfo() {
return (
<div>
<h1>Andi</h1>
<p>Developer</p>
</div>
);
}
// ✅ Pakai Fragment tanpa extra DOM
function UserInfo() {
return (
<>
<h1>Andi</h1>
<p>Developer</p>
</>
);
}
// ✅ Fragment dengan key (untuk list)
function UserList({ users }) {
return users.map(user => (
<Fragment key={user.id}>
<h3>{user.name}</h3>
<p>{user.email}</p>
</Fragment>
));
}
saya lebih suka Fragment <>...</> kalau tidak butuh styling wrapper, biar DOM tidak penuh div kosong. tapi kalau butuh key di list, pakai <Fragment key={...}>.
15. tips kecil yang sering kelupaan
- nama component pakai PascalCase,
UserCardbukanuserCard, file jugaUserCard.jsx - satu component satu file untuk yang reusable, kalau kecil boleh digabung
- kalau mau aman, pakai TypeScript atau PropTypes biar props tidak nyasar
keyjangan pakai index kalau list bisa tambah hapus- untuk component berat,
React.memo()lumayan bantu kurangin re-render - function yang dikirim ke child, bungkus
useCallbackbiar tidak bikin function baru tiap render - logic dan UI dipisah, saya biasanya bikin custom hook kayak useFetch atau useForm
- import absolute biar rapi, di vite.config.js set alias
@kesrc - test pakai React Testing Library plus Vitest, jangan lupa
- jangan inline function terlalu banyak di JSX, tiap render bikin function baru, tapi jangan juga over optimize sebelum ada masalah
16. catatan 2026, React 19 sudah stabil
kalau kalian start project baru di 2026, React 19 sudah stabil sejak 5 Desember 2024 dan jadi default di Next.js 15. pola di atas masih jalan, tapi ada yang lebih ringkas:
Actions, form tanpa useState panjang
dulu form saya butuh 30 baris useState buat loading dan error. di React 19 cukup pakai Actions:
import { useActionState } from 'react';
import { updateName } from './actions';
function NameForm() {
const [error, submitAction, isPending] = useActionState(updateName, null);
return (
<form action={submitAction}>
<input name="name" />
<button disabled={isPending}>{isPending ? 'Menyimpan...' : 'Simpan'}</button>
{error && <p>{error}</p>}
</form>
);
}
ada juga useOptimistic buat UI optimis dan useFormStatus buat status di button child. enaknya, form tetap bisa submit walau JavaScript belum load.
hook use()
buat ambil Promise atau Context tanpa useEffect:
import { use } from 'react';
function Comments({ commentsPromise }) {
const comments = use(commentsPromise);
return <ul>{comments.map(c => <li key={c.id}>{c.text}</li>)}</ul>;
}
Compiler
React Compiler sekarang bisa auto memo, jadi React.memo, useMemo, dan useCallback sering tidak perlu lagi. aktifkan lewat babel-plugin-react-compiler atau Next.js 15 experimental.reactCompiler: true.
Server Components
di Next.js 15, component default jalan di server, bisa akses DB langsung. kalau butuh useState, tambah "use client" di baris paling atas. jangan campur logic client di Server Component ya.
kalau project kalian masih kecil di bawah 50 component, langsung upgrade tidak apa-apa. kalau sudah 200 component ke atas, saya sarankan coba di branch dulu, tunggu ekosistem UI library selesai adaptasi.
Kesimpulan
- component itu blok UI yang bisa dipakai ulang, tulisnya sebagai function yang return JSX
- JSX itu kayak HTML di dalam JavaScript, tapi ingat className bukan class
- props itu input yang read-only, children buat slot konten
- state pakai useState, side effect pakai useEffect
- render kondisional pakai ternary atau
&&, tapi hati-hati 0 - list wajib
keyyang stabil dan unik - Fragment
<>...</>buat bungkus tanpa nambah div - composition lebih enak daripada inheritance untuk UI kompleks
- untuk lanjutan, ada props dan state lebih dalam dan event handling form
Baca Juga Mengenai :
Pertanyaan yang Sering Diajukan
Apa itu component di React?
component adalah blok UI yang reusable, ditulis sebagai function yang return JSX. analoginya seperti fungsi biasa: nerima input (props), return output (UI). component bisa di-nesting dan dipakai berulang kali di aplikasi.
Apa bedanya functional component dan class component?
functional component = function biasa yang return JSX. class component = class yang extends React.Component dan punya render() method. sejak React 16.8 (hooks), functional component jadi standar industri. class component jarang dipakai lagi kecuali untuk library lama.
Apa itu JSX?
JSX (JavaScript XML) adalah syntax extension untuk JavaScript yang memungkinkan penulisan HTML-like code di dalam JavaScript. contoh: <h1>Hello</h1> itu JSX. di-compile jadi React.createElement() di belakang layar.
Apa itu props di React?
props adalah input component,类似于 function parameter. props read-only (immutable). parent component kirim props ke child via attribute, child akses via parameter function. perubahan props di child tidak akan trigger re-render di parent.
Apa itu children props?
children adalah props khusus yang isinya konten di antara tag component. contoh: <Card>Hello</Card>, "Hello" adalah children. dipakai untuk composition: Card membungkus konten apapun tanpa tahu isinya.
Kenapa nama component harus huruf kapital?
React membedakan component dan HTML element berdasarkan huruf pertama. huruf kecil = HTML element (<div>). huruf besar = component (<Card>). tanpa aturan ini, React bingung apakah itu tag HTML biasa atau custom component.
Apa itu React Fragment?
Fragment (<>...</> atau <Fragment>) adalah wrapper tanpa tambah DOM element. dipakai saat return banyak element tanpa bisa pakai satu parent. bedanya dengan div: Fragment tidak render extra node di HTML output.
Bagaimana cara import component di React?
pakai ES6 import: import Greeting from "./components/Greeting". named export: import {Greeting} from "./components". pastikan path benar dan ada file index.js untuk folder (opsional).

