Interaktif Tanpa Batas: Mengelola State dengan Hook useState di React (Part 5)

Rifqi An Rifqi An
Februari 27, 2026


Interaktif Tanpa Batas: Mengelola State dengan Hook useState di React (Part 5)

Selamat datang kembali, para ksatria keyboard dan ratu coding! Setelah kemarin kita udah ngulik-ngulik gimana caranya komponen bisa ngobrol lewat props (Part 4), sekarang kita mau naik level nih. Siap-siap, karena kita akan masuk ke inti jantungnya interaktivitas di aplikasi React: State. Dan nggak sembarang state, kita mau kenalan sama Hook useState, si pahlawan super yang bikin aplikasi kamu bisa mikir, berubah, dan merespon kayak manusia! Penasaran kan gimana caranya aplikasi bisa punya "ingatan" sendiri? Yuk, kita bedah tuntas!

Daftar Isi

Apa Itu State dan Kenapa Penting Banget di React?

Oke, sebelum kita terjun bebas ke useState, kita samakan persepsi dulu. Apa sih state itu? Gampangnya, state itu adalah data internal suatu komponen yang bisa berubah seiring waktu dan akan memicu render ulang (rerender) komponen tersebut beserta turunannya. Kalau dianalogikan, state itu kayak "memorinya" komponen React kamu.

Coba bayangkan kamu punya tombol "Like" di Instagram. Saat kamu klik, angkanya nambah kan? Nah, angka "like" itu adalah sebuah state. Atau kamu punya keranjang belanja online, jumlah item di dalamnya juga state. Kalau nggak ada state, aplikasi kamu cuma jadi pajangan doang, nggak bisa diajak interaksi. Mati gaya!

Kenalan Sama useState: Si Pahlawan Interaksi

Dulu banget, waktu React masih bayi, urusan state ini ribetnya minta ampun kalau pakai functional component. Kita harus pakai class component yang lumayan banyak boilerplate code-nya. Tapi sejak ada React Hooks di versi 16.8, semuanya berubah! Salah satu hooks paling fundamental dan sering kita pakai adalah useState.

useState ini memungkinkan kita menambahkan "state" ke dalam functional component. Jadi, nggak perlu lagi pakai class component cuma buat ngurusin state. Hidup jadi lebih mudah, kode lebih bersih, dan kita bisa lebih fokus ngopi daripada mikirin this yang suka bikin pusing tujuh keliling!

Begini nih penampakan dasar useState:


import React, { useState } from 'react';

function MyComponent() {
  // Deklarasi state "count" dengan nilai awal 0
  // `count` adalah variabel state, `setCount` adalah fungsi untuk mengupdate `count`
  const [count, setCount] = useState(0);

  // ... logika komponen lainnya
}

Nah, dari kode di atas, kita bisa lihat useState itu mengembalikan sepasang nilai: [currentState, setterFunction].

  • currentState: Ini adalah nilai state kamu saat ini.
  • setterFunction: Ini adalah fungsi yang bakal kamu pakai buat mengubah (mengupdate) nilai state tersebut. Ingat ya, jangan pernah langsung mengubah nilai state, selalu pakai setter function ini! Kalau nggak, bisa-bisa aplikasi kamu ngambek, nggak mau di-render ulang.
Dan nilai yang kamu kasih ke useState(nilaiAwal) itu bakal jadi nilai awal (initial state) dari state kamu.

Cara Pakai useState: Nggak Ribet Kok!

Mari kita langsung praktik pakai contoh sederhana: sebuah tombol penghitung atau "counter". Setiap kali tombol diklik, angka counternya nambah. Gampang banget kan? Ini dia kodenya:


import React, { useState } from 'react';

function CounterApp() {
  const [count, setCount] = useState(0); // State `count` dengan nilai awal 0

  const incrementCount = () => {
    // Memanggil setter function `setCount` untuk mengupdate `count`
    setCount(count + 1);
    console.log("Count sekarang:", count); // Hati-hati, ini mungkin nilai lama! Baca penjelasan di bawah.
  };

  const decrementCount = () => {
    setCount(count - 1);
  };

  return (
    <div style={{ textAlign: 'center', marginTop: '50px' }}>
      <h2>Aplikasi Penghitung Ngopi</h2>
      <p>Jumlah gelas kopi yang sudah kamu habiskan: <strong>{count}</strong></p>
      <button onClick={incrementCount} style={{ padding: '10px 20px', margin: '5px', backgroundColor: '#4CAF50', color: 'white', border: 'none', borderRadius: '5px', cursor: 'pointer' }}>
        Tambah Kopi (+1)
      </button>
      <button onClick={decrementCount} style={{ padding: '10px 20px', margin: '5px', backgroundColor: '#f44336', color: 'white', border: 'none', borderRadius: '5px', cursor: 'pointer' }}>
        Kurang Kopi (-1)
      </button>
      <p><em>Warning: Konsumsi kopi berlebihan dapat menyebabkan bug di otak!</em></p>
    </div>
  );
}

export default CounterApp;

Kalau kamu coba kode di atas, kamu bakal lihat deh, setiap kali tombol "Tambah Kopi" diklik, angka count langsung nambah dan UI-nya otomatis ke-update. Ini dia keajaiban React! Ketika state berubah, React akan otomatis me-render ulang komponen yang terpengaruh.

Penting! Kalau kamu perhatikan console.log di dalam incrementCount, mungkin kamu bakal kaget kok nilainya selalu ketinggalan satu. Ini karena setter function setCount itu adalah operasi yang asynchronous! React bakal meng-update state dan me-render ulang komponen di "batch" berikutnya. Jadi, pas console.log dijalankan, nilai count yang diakses masih yang lama. Untuk mendapatkan nilai terbaru secara langsung setelah update, biasanya kita pakai useEffect (yang akan kita bahas di part selanjutnya, pantengin terus!). Atau, kalau cuma untuk update yang bergantung pada nilai state sebelumnya, lebih aman pakai callback function di setter:


  const incrementCountSafe = () => {
    setCount(prevCount => prevCount + 1); // Ini lebih aman dan direkomendasikan!
  };

Dengan cara prevCount => prevCount + 1, kita memastikan bahwa kita selalu bekerja dengan nilai state yang paling baru, bahkan jika ada banyak update state yang terjadi secara cepat. Ini penting banget buat menghindari bug-bug aneh!

Mengupdate State yang Kompleks: Object dan Array

Nggak cuma angka atau string doang yang bisa jadi state, object dan array juga bisa! Tapi ada sedikit triknya nih, karena React itu menganut prinsip immutability. Artinya, kalau kamu mau update object atau array di state, kamu nggak boleh langsung mengubah object/array aslinya. Kamu harus membuat salinan baru, lalu mengubah salinan itu, baru deh di-set ke state. Ini penting banget biar React bisa deteksi perubahan dan me-render ulang dengan benar.

State Berupa Object

Misalnya kamu punya state profil user:


import React, { useState } from 'react';

function UserProfileEditor() {
  const [user, setUser] = useState({
    name: 'Budi Santoso',
    age: 30,
    occupation: 'Fullstack Developer',
    isLoggedIn: false
  });

  const handleLoginToggle = () => {
    setUser(prevUser => ({
      ...prevUser, // Copas semua properti user sebelumnya
      isLoggedIn: !prevUser.isLoggedIn // Lalu ubah properti `isLoggedIn` saja
    }));
  };

  const updateOccupation = (newOccupation) => {
    setUser(prevUser => ({
      ...prevUser,
      occupation: newOccupation
    }));
  };

  return (
    <div style={{ border: '1px solid #ccc', padding: '20px', borderRadius: '8px', margin: '20px auto', maxWidth: '400px' }}>
      <h3>Profil User</h3>
      <p>Nama: <strong>{user.name}</strong></p>
      <p>Umur: <strong>{user.age}</strong></p>
      <p>Pekerjaan: <strong>{user.occupation}</strong></p>
      <p>Status Login: <strong>{user.isLoggedIn ? 'Online' : 'Offline'}</strong></p>
      <button onClick={handleLoginToggle} style={{ marginRight: '10px', padding: '8px 15px', backgroundColor: '#007bff', color: 'white', border: 'none', borderRadius: '5px', cursor: 'pointer' }}>
        {user.isLoggedIn ? 'Logout' : 'Login'}
      </button>
      <button onClick={() => updateOccupation('Software Engineer')} style={{ padding: '8px 15px', backgroundColor: '#28a745', color: 'white', border: 'none', borderRadius: '5px', cursor: 'pointer' }}>
        Ganti Jadi Software Engineer
      </button>
    </div>
  );
}

export default UserProfileEditor;

Perhatikan penggunaan spread syntax (...prevUser). Ini penting banget buat "mengcopas" semua properti dari object prevUser ke object baru, baru setelah itu kita timpa properti yang mau diubah (isLoggedIn atau occupation). Kalau nggak pakai ...prevUser, properti lain yang nggak kamu sebut bakal hilang lho!

State Berupa Array

Sama halnya dengan array, kamu nggak boleh langsung .push(), .pop(), atau mengubah elemennya secara langsung. Kamu harus membuat array baru. Ini contoh buat daftar tugas (To-Do List) sederhana:


import React, { useState } from 'react';

function TodoList() {
  const [todos, setTodos] = useState([
    'Belajar React Hooks (Part 5)',
    'Ngopi item sambil debugging',
    'Revisi kode yang bikin error kemarin',
    'Push ke production (bismillah!)'
  ]);
  const [newTodo, setNewTodo] = useState('');

  const addTodo = () => {
    if (newTodo.trim() === '') return; // Jangan tambahkan todo kosong
    setTodos(prevTodos => [...prevTodos, newTodo]); // Buat array baru dengan todo baru
    setNewTodo(''); // Kosongkan input
  };

  const removeTodo = (indexToRemove) => {
    setTodos(prevTodos => prevTodos.filter((_, index) => index !== indexToRemove));
  };

  return (
    <div style={{ border: '1px solid #ccc', padding: '20px', borderRadius: '8px', margin: '20px auto', maxWidth: '400px' }}>
      <h3>Daftar Tugas Programmer</h3>
      <ul style={{ listStyleType: 'none', padding: 0 }}>
        {todos.map((todo, index) => (
          <li key={index} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '8px 0', borderBottom: '1px dotted #eee' }}>
            {todo}
            <button onClick={() => removeTodo(index)} style={{ backgroundColor: '#dc3545', color: 'white', border: 'none', borderRadius: '3px', padding: '5px 10px', cursor: 'pointer' }}>
              X
            </button>
          </li>
        ))}
      </ul>
      <div style={{ marginTop: '15px' }}>
        <input
          type="text"
          value={newTodo}
          onChange={(e) => setNewTodo(e.target.value)}
          placeholder="Tambahkan tugas baru..."
          style={{ width: 'calc(100% - 80px)', padding: '8px', borderRadius: '4px', border: '1px solid #ddd', marginRight: '10px' }}
        />
        <button onClick={addTodo} style={{ padding: '8px 15px', backgroundColor: '#007bff', color: 'white', border: 'none', borderRadius: '4px', cursor: 'pointer' }}>
          Tambah
        </button>
      </div>
      {todos.length === 0 && <p style={{ color: '#666', fontStyle: 'italic', marginTop: '10px' }}>Wah, semua tugas sudah beres! Saatnya ngoding santuy.</p>}
    </div>
  );
}

export default TodoList;

Lihat di fungsi addTodo dan removeTodo! Kita selalu membuat array baru. Untuk addTodo, kita pakai spread syntax [...prevTodos, newTodo] untuk menggabungkan array lama dengan item baru. Sedangkan untuk removeTodo, kita pakai metode filter() yang juga mengembalikan array baru tanpa item yang dihapus. Keren kan?

Rules of Engagement: Hal-Hal Penting Soal useState

Ada beberapa aturan main yang harus kamu patuhi kalau nggak mau useState kamu error atau berulah:

  • Panggil dari Top Level: Hooks (termasuk useState) hanya boleh dipanggil di level paling atas dari functional component atau custom Hook kamu. Nggak boleh di dalam perulangan (for/while), kondisi (if/else), atau fungsi bersarang. Kalau dilanggar, auto pusing nyari bugnya!
  • Hanya dari Functional Component: Jelas banget, useState itu buat functional component. Jangan coba-coba pakai di class component ya.
  • Jangan Langsung Ubah State: Selalu gunakan fungsi setter (misalnya setCount, setTodos) untuk mengubah nilai state. Ini kunci!
  • Multiple useState Allowed: Kamu bisa pakai useState berkali-kali dalam satu komponen untuk mengelola state yang berbeda-beda. Jadi, nggak perlu satu useState buat semua data. Lebih baik pecah-pecah biar gampang diatur.

useState vs. useReducer: Kapan Pilih Yang Mana? (Sekilas Saja!)

Mungkin ada yang bertanya, "Kak, kalau state-nya makin kompleks, useState masih oke nggak?" Nah, untuk skenario state yang sangat kompleks, di mana satu aksi bisa memengaruhi beberapa bagian state sekaligus, atau logic updatenya rumit, React punya Hook lain namanya useReducer. Kita akan bahas ini lebih detail di part selanjutnya. Tapi intinya, useState itu solusi ideal untuk state sederhana (angka, string, boolean, object/array kecil) dan ketika logic updatenya gampang.

Kesimpulan: State Itu Nyawa Aplikasi React Kamu!

Selamat! Kamu sekarang sudah mengenal salah satu Hook paling penting di React: useState. Kamu sudah tahu bagaimana mendeklarasikan state, menginisialisasi nilainya, dan yang paling penting, bagaimana cara mengupdatenya baik untuk nilai sederhana maupun object dan array. Dengan useState, kamu sudah punya senjata ampuh buat bikin aplikasi React kamu jadi lebih interaktif dan dinamis.

Ingat, kalau ada error, jangan panik! Itu tandanya kamu lagi belajar. Ngopi dulu, santuy, terus cek lagi kodenya. Mungkin ada typo, atau lupa pakai spread operator. Semangat ngodingnya, ya!

Latihan Ngoding Ngaco: Misi Penyelamatan Kucing Online!

Oke, biar makin jago, yuk kita kerjakan studi kasus yang agak ngaco tapi seru ini! Bayangkan kamu adalah seorang "Cat Whisperer Developer" yang ditugaskan membuat aplikasi sederhana untuk mengelola status kucing-kucing lucu di penampungan online. Kucing-kucing ini punya mood yang naik turun dan kadang butuh diselamatkan dari kebosanan!

Buat sebuah komponen React bernama CatRescueApp. Di dalamnya, kamu harus menggunakan useState untuk:

  • Mengelola sebuah array of objects untuk daftar kucing. Setiap object kucing harus punya properti:
    • id: (number unik)
    • name: (string, contoh: "Miko", "Bella")
    • mood: (string, contoh: "Happy", "Grumpy", "Sleepy")
    • rescueCount: (number, berapa kali kucing ini sudah "diselamatkan" dari kebosanan)
  • Tampilkan daftar kucing ini. Untuk setiap kucing, tampilkan nama, mood, dan rescueCount-nya.
  • Buatlah tombol "Cheer Up!" di samping setiap kucing. Ketika tombol ini diklik:
    • mood kucing tersebut berubah menjadi "Ecstatic!".
    • rescueCount kucing tersebut bertambah 1.
    • Penting: Ingat prinsip immutability saat mengupdate array of objects! Kamu harus membuat array baru dengan object kucing yang sudah diupdate.
  • Tambahkan juga sebuah input text dan tombol "Add New Cat" di bagian bawah.
    • Pengguna bisa mengetik nama kucing baru.
    • Ketika tombol diklik, kucing baru akan ditambahkan ke daftar dengan mood awal "Neutral" dan rescueCount 0. Jangan lupa kasih ID unik!

Gimana, siap jadi pahlawan bagi kucing-kucing online? Selamat ngoding dan jangan sampai bug-nya bikin kucingmu ikutan grumpy ya!

= useState(initialValue);`. The other monitor shows a dynamic, interactive UI of a simple React app. Above the programmer's head, a glowing lightbulb emits rays with subtle React logos. A half-empty coffee mug with a "bug" symbol in its steam sits beside the keyboard. In a corner, a small sticky note or digital overlay clearly says "Part 5". The background is a bright, modern office space with subtle tech elements. The overall color scheme should be appealing and energetic, suitable for attracting attention on Google Discover. The mood should convey learning, excitement, and a touch of programmer quirkiness.]

Bagikan Artikel Ini