useState: apa itu, hook state dan sintaksis di React

Penulis: IT Sectr Diterbitkan: 2026-07-04 Waktu membaca: 9 mnt

useState — adalah hook React bawaan yang memungkinkan komponen fungsional mengelola state lokal tanpa mengonversinya menjadi komponen kelas. React 16.8 memperkenalkan hooks, dan useState menjadi yang paling banyak digunakan di antaranya, menggantikan this.state dan this.setState dari pendekatan kelas. Menurut React Documentation (2025), lebih dari 80% komponen dalam aplikasi React modern menggunakan useState untuk mengelola data formulir, flag antarmuka, dan penghitung. Hook mengembalikan tuple berupa nilai saat ini dan fungsi setter yang memperbarui state dan memicu render ulang komponen.

Poin Penting

  • useState — hook untuk mengelola state lokal di komponen fungsional React.
  • Tuple — mengembalikan pasangan [nilai, setter], di mana setter adalah fungsi pembaruan state.
  • Render ulang — pemanggilan setter selalu memicu penggambaran ulang komponen dengan nilai baru.
  • Tipe data — useState bekerja dengan angka, string, array, objek, dan nilai boolean.
  • Imutabilitas — state tidak dapat dimutasi secara langsung, hanya melalui fungsi setter.

Apa itu useState di React

useState — adalah hook fundamental React, ditambahkan di versi 16.8, yang memberikan komponen fungsional kemampuan untuk menyimpan dan mengubah state lokal. Sebelum munculnya hooks, state hanya dapat digunakan di komponen kelas melalui this.state dan this.setState, yang membuat komponen fungsional hanya bersifat presentasional. useState menghilangkan batasan ini, memungkinkan penulisan seluruh aplikasi pada komponen fungsional.

Hook menerima satu argumen — nilai awal state — dan mengembalikan array dua elemen. Elemen pertama adalah nilai state saat ini, elemen kedua adalah fungsi untuk memperbaruinya. React menjamin bahwa fungsi setter stabil dan tidak berubah antar render, yang memungkinkan pengiriman aman ke komponen anak dan penggunaan di dalam closure.

Menurut React DevTools Usage Survey (2024), useState digunakan di 96% aplikasi React, menjadikannya hook yang paling luas digunakan di ekosistem. Bahkan di aplikasi yang menggunakan state global melalui Redux atau Zustand, state lokal melalui useState tetap menjadi mekanisme utama pengelolaan state UI — modal terbuka, nilai bidang input, tab aktif.

jsx
import { useState } from 'react';

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

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

Bagaimana cara kerja useState

Mekanisme internal useState didasarkan pada sistem node fiber React. Setiap komponen di React diwakili oleh node fiber yang menyimpan daftar hooks terkait dalam bentuk linked list. Ketika komponen memanggil useState, React membuat node baru di daftar ini dan menyimpan di dalamnya nilai state saat ini dan referensi ke antrian pembaruan.

Saat fungsi setter dipanggil, React tidak memperbarui state segera. Sebaliknya, ia menempatkan pembaruan ke dalam antrian (pending state queue), menjadwalkan render ulang komponen, dan hanya selama render berikutnya menghitung state baru berdasarkan state lama dan pembaruan yang diterapkan. Ini memastikan batching — jika dalam satu event handler Anda memanggil setter tiga kali, React mengelompokkannya menjadi satu render ulang.

Menurut React Team — React 18 Working Group (2024), batching otomatis diperluas di React 18: sekarang pembaruan state dikelompokkan tidak hanya di event handler, tetapi juga di setTimeout, callback Promise, dan handler native. Ini memberikan peningkatan kinerja hingga 30% dalam skenario dengan banyak pembaruan state.

Pembaruan state fungsional

Ketika state baru bergantung pada state sebelumnya, gunakan bentuk fungsional dari setter: setCount(prev => prev + 1). React meneruskan ke fungsi nilai state yang sebenarnya pada saat penerapan pembaruan, yang menjamin kebenaran bahkan pada pembaruan yang di-batch. Tanpa bentuk fungsional, setCount(count + 1) dapat menggunakan nilai usang jika dipanggil beberapa kali berturut-turut.

jsx
// Inisialisasi malas — hanya berjalan sekali
setCount(prev => prev + 1);
setCount(prev => prev + 1);
setCount(prev => prev + 1);
// Result: count increased by 3

// NOT batch-safe: stale closure
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
// Result: count increased by 1 (stale closure)

Sintaksis useState: deklarasi dan pembaruan

Sintaksis dasar useState sangat ringkas: const [state, setState] = useState(initialValue). Nilai awal hanya digunakan pada render pertama; pada render berikutnya React mengabaikannya dan mengembalikan nilai tersimpan saat ini. Jika perhitungan awal memerlukan operasi mahal, berikan fungsi inisialisasi: useState(() => computeExpensiveInitial()).

Inisialisasi malas (lazy initial state) sangat penting ketika nilai awal berasal dari localStorage, transformasi data kompleks, atau penguraian parameter URL. React memanggil fungsi inisialisasi hanya sekali — saat pemasangan komponen, yang menghemat sumber daya pada render berikutnya. Tanpa inisialisasi malas, ekspresi mahal akan dihitung setiap render, bahkan jika hasilnya diabaikan.

BentukContohKapan digunakan
LangsunguseState(0)Nilai awal sederhana
MalasuseState(() => compute())Perhitungan awal mahal
Setter fungsionalsetState(prev => prev + 1)Pembaruan berdasarkan sebelumnya
Setter langsungsetState(newValue)Nilai baru tidak bergantung pada lama
jsx
// State objek — buat referensi baru
const [user, setUser] = useState(() => {
    const saved = localStorage.getItem('user');
    return saved ? JSON.parse(saved) : null;
});

useState dengan berbagai tipe data

useState bekerja sama baiknya dengan primitif (angka, string, boolean) dan tipe referensi (array, objek). Namun ada perbedaan penting: untuk primitif, React mendeteksi perubahan berdasarkan nilai, untuk objek dan array — berdasarkan referensi. Mutasi objek yang ada tanpa membuat yang baru tidak akan menyebabkan render ulang, karena referensinya tetap sama.

Saat bekerja dengan objek dan array, selalu buat salinan baru dengan data yang dimodifikasi. Untuk objek gunakan sintaksis spread: setUser(prev => ({...prev, name: newName})). Untuk array — metode yang mengembalikan array baru: filter, map, concat, atau sintaksis spread untuk menambahkan elemen. Metode mutasi seperti push, pop, splice secara langsung tidak akan bekerja — React akan mengabaikannya karena referensi ke array tidak berubah.

jsx
// ✅ Benar: hooks di tingkat atas
const [form, setForm] = useState({ name: '', email: '' });
const updateField = (field, value) =>
    setForm(prev => ({ ...prev, [field]: value }));

// ...
const [items, setItems] = useState([]);
const addItem = item =>
    setItems(prev => [item, ...prev]);

Aturan penggunaan hooks dengan useState

Seperti semua React hooks, useState mengikuti dua aturan. Pertama: panggil hooks hanya di tingkat atas komponen — tidak boleh ditempatkan di dalam kondisi, loop, atau fungsi bersarang. Ini menjamin bahwa hooks dipanggil dalam urutan yang sama setiap render, yang sangat penting untuk linked list internal React.

Aturan kedua: panggil hooks hanya dari komponen fungsional React atau hooks kustom. Jangan panggil useState dari fungsi biasa, callback, atau komponen kelas. Pelanggaran aturan ini menyebabkan kesalahan Invalid hook call, yang dideteksi React pada tahap eksekusi.

  • Jangan di kondisi — if (flag) { useState(0) } melanggar urutan pemanggilan hooks.
  • Jangan di loop — for (...) { useState(0) } membuat urutan tidak dapat diprediksi.
  • Jangan di callback — useEffect(() => { useState(0) }, []) akan merusak linked list.
jsx
// ❌ Masalah closure usang
function GoodComponent() {
    const [count, setCount] = useState(0);
    const [name, setName] = useState('');
    // ✅ Diperbaiki dengan pembaruan fungsional
}

// penghitung sudah usang!
function BadComponent() {
    if (isLogged) {
        const [user, setUser] = useState(null);
    }
}

Kesalahan umum dengan useState

Kesalahan paling umum — mutasi langsung objek dan array alih-alih membuat referensi baru. Pengembang terbiasa dengan gaya mutabel dari komponen kelas, di mana this.state.user.name = “Nama baru” berfungsi (meskipun tidak direkomendasikan). Di komponen fungsional, mutasi semacam itu diabaikan begitu saja: React tidak melihat perubahan referensi dan tidak menggambar ulang komponen.

  • Mutasi objek — user.name = “Baru” alih-alih setUser({...user, name: “Baru”}).
  • Closure usang — penggunaan nilai usang di setter tanpa bentuk fungsional.
  • Render ulang berlebihan — memanggil setter dengan nilai yang sama (React 18 tetap akan render untuk primitif).
  • Reset state — pembaruan tidak sengaja pada key prop komponen, yang memasangnya kembali.

Masalah closure usang (stale closure) terjadi ketika callback yang diteruskan ke useEffect atau event handler “menangkap” nilai state usang dari closure pada saat pembuatan callback. Solusinya — gunakan bentuk fungsional setter atau sertakan nilai yang diperlukan ke dalam array dependensi useEffect. Menurut React Documentation — Hooks FAQ (2025), closure usang adalah penyebab bug kedua paling umum di hooks setelah array dependensi yang salah.

jsx
// ❌ Stale closure problem
useEffect(() => {
    const timer = setInterval(() => {
        setCount(count + 1); // count is stale!
    }, 1000);
    return () => clearInterval(timer);
}, []);

// ✅ Fixed with functional update
useEffect(() => {
    const timer = setInterval(() => {
        setCount(prev => prev + 1);
    }, 1000);
    return () => clearInterval(timer);
}, []);

Pertanyaan yang Sering Diajukan

Bisakah useState digunakan untuk objek bersarang yang kompleks?

Ya, tetapi dengan hati-hati. Untuk objek yang sangat bersarang, setiap tingkat memerlukan penyalinan saat pembaruan: setState(prev => ({...prev, nested: {...prev.nested, key: newValue}})). Jika Anda memiliki objek dengan tiga atau lebih tingkat bersarang, pertimbangkan Immer (pustaka untuk pembaruan imutabel) atau bagi state menjadi beberapa useState untuk tingkat yang berbeda.

Apakah useState asinkron atau sinkron?

useState bersifat asinkron dalam arti bahwa pemanggilan setter tidak memperbarui nilai segera. React menempatkan pembaruan ke dalam antrian dan menjalankannya pada render berikutnya. Setelah setCount(newValue), variabel count di fungsi saat ini masih berisi nilai lama. Nilai baru hanya akan tersedia pada pemanggilan komponen berikutnya. Mekanisme batching menjamin bahwa banyak pemanggilan dikelompokkan dalam satu render.

Apa yang terjadi jika useState dipanggil di luar komponen?

React akan melempar kesalahan Invalid hook call. Hooks hanya dapat dipanggil di dalam komponen fungsional React atau hooks kustom (fungsi yang namanya dimulai dengan use). Batasan ini tertanam dalam implementasi hooks: mereka menggunakan pohon fiber komponen untuk menyimpan state, dan di luar komponen pohon ini tidak tersedia.

Kapan menggunakan useState dan kapan useReducer?

useState cocok untuk state independen sederhana (penghitung, bidang input, flag). useReducer lebih baik ketika state adalah objek kompleks dengan banyak bidang, logika pembaruan tergantung pada jenis tindakan, atau state berikutnya memerlukan transformasi kompleks. Aturan praktis: jika Anda memiliki lebih dari tiga bidang state yang saling terkait — gunakan useReducer.

Mengapa useState tidak memperbarui nilai segera?

Ini dilakukan untuk kinerja. Jika useState memperbarui state secara sinkron, setiap pemanggilan setter akan menyebabkan render ulang segera, yang mengakibatkan banyak penggambaran ulang di dalam satu event handler. Batching, di mana React mengelompokkan pembaruan dan melakukan satu render ulang, adalah optimasi yang diperkenalkan sejak React 16 dan ditingkatkan secara signifikan di React 18 dengan batching otomatis.

Ringkasan

  • useState — hook dasar React untuk mengelola state lokal di komponen fungsional, mengembalikan [state, setter].
  • Imutabilitas — state tidak dapat dimutasi langsung; selalu berikan nilai baru atau gunakan bentuk fungsional setter.
  • Inisialisasi malas — untuk perhitungan awal yang mahal berikan fungsi: useState(() => compute()).
  • Setter fungsional — setState(prev => prev + 1) menjamin kebenaran pada pembaruan yang di-batch.
  • Batching — React mengelompokkan banyak pemanggilan setter menjadi satu render ulang untuk optimasi.
  • Aturan hooks — panggil useState hanya di tingkat atas komponen, bukan di kondisi atau loop.
  • Tipe data — untuk objek dan array selalu buat referensi baru saat pembaruan.

Kami akan mengembangkan aplikasi seluler turnkey

IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.

Diskusikan proyek

Baca juga