React Hooks itu apa sih sebenernya? Penjelasan simpel buat kamu

React Hooks itu apa sih sebenernya? Penjelasan simpel buat kamu
Photo by Rahul Mishra / Unsplash

Pernah denger soal React Hooks? Kalau kamu lagi belajar atau udah pakai React buat bikin website atau aplikasi, pasti udah familiar atau setidaknya pernah denger istilah ini. React Hooks ini kayak "game changer" banget di ekosistem React, terutama buat developer yang suka ngoding pakai Functional Component.

Nah, sebelum kita masuk ke dalam-dalamnya, mungkin ada yang nanya, "Emang kenapa sih butuh Hooks? Kan udah ada Class Component?" Oke, gini ceritanya...

Dulu Banget: Era Class Component

Sebelum ada Hooks (mulai React versi 16.8), kalau kamu mau bikin komponen yang punya "state" (inget ya, state itu data yang bisa berubah dan mempengaruhi tampilan komponen) atau ngurusin "side effect" (kayak ngambil data dari API, setting timer, atau interaksi sama browser API), kamu wajib pakai Class Component.

Contoh state di Class Component:

jsx
class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }render() {
    return (
      
        Kamu klik sebanyak {this.state.count} kali
         this.setState({ count: this.state.count + 1 })}>
          Klik Aku
        
      
    );
  }
}

Kelihatan kan, ada class, ada constructor, ada this.state, dan ada this.setState. Terus kalau mau ngurusin side effect, kita pakai yang namanya "Lifecycle Methods", kayak componentDidMount (ketika komponen pertama kali muncul), componentDidUpdate (ketika state atau props berubah), atau componentWillUnmount (ketika komponen hilang dari layar).

Contoh side effect (update judul halaman) di Class Component:

jsx
class TitleUpdater extends React.Component {
  componentDidMount() {
    document.title = Halaman Saya;
  }componentDidUpdate() {
    document.title = Kamu klik sebanyak ${this.state.count} kali; // Ini dari state Counter, contoh aja ya
  }

Nah, ini nih beberapa masalah yang sering ditemui pakai Class Component:

  1. Bingung sama this: Hayoo, siapa yang suka salah binding this di event handler? Ini salah satu sumber kebingungan paling umum, apalagi buat yang baru belajar JavaScript atau React.
  2. Logic yang Tercerai Berai: Logic yang berhubungan sama satu fitur sering kali harus dipisah-pisah di berbagai Lifecycle Methods. Misalnya, data fetching di componentDidMount dan cleanup (kayak unsubscribe) di componentWillUnmount. Ini bikin kode jadi susah dibaca dan di-maintain, terutama kalau komponennya udah kompleks.
  3. Susah Re-use Logic State/Effect: Kalau kamu punya logic yang sama (misalnya logic buat toggle modal, atau logic buat ngambil data) yang pengen dipake di beberapa komponen berbeda, lumayan ribet tuh pakai Class Component. Biasanya pakai Higher-Order Components (HOCs) atau Render Props, yang kadang bikin struktur komponen jadi nested dan susah dibaca (kayak "wrapper hell").
  4. Code yang Lebih Panjang: Dibanding Functional Component, Class Component itu kodenya cenderung lebih panjang karena butuh class, constructor, super(), this, dll.

Nah, berangkat dari masalah-masalah inilah, tim React memperkenalkan React Hooks. Tujuannya simple: Bikin Functional Component bisa punya state dan ngurusin side effect, sehingga developer bisa bikin aplikasi React yang powerful tanpa harus pakai Class Component sama sekali.

Jadi, React Hooks Itu Apa Sih?

Intinya, React Hooks itu adalah fungsi-fungsi spesial yang memungkinkan kamu "nempel" (hook into) fitur-fitur React kayak state dan lifecycle methods dari Functional Component.

Dengan Hooks, Functional Component yang tadinya cuma bisa nerima props dan nge-render UI (sering disebut "stateless functional component"), sekarang bisa ngatur state-nya sendiri dan ngelakuin side effect. Makanya sekarang lebih sering disebut "Functional Component" aja, karena udah nggak stateless lagi.

Keunggulan utama Hooks adalah:

  • Lebih Simpel dan Mudah Dibaca: Code jadi lebih pendek, nggak ada this yang bikin pusing.
  • Logic yang Relevan Jadi Satu: Logic yang tadinya kepisah di Lifecycle Methods bisa dikumpulin jadi satu di useEffect, atau bahkan dibikin Custom Hook sendiri.
  • Re-use Logic Jadi Gampang: Bisa bikin Custom Hook buat nge-share logic stateful antar komponen.
  • Nggak Perlu Pake Class: Kalau kamu lebih suka gaya penulisan pakai fungsi, Hooks ini pas banget.

Oke, sekarang kita kenalan sama Hooks yang paling sering dipake:

1. useState (Buat Ngatur State)

Ini adalah Hook paling dasar dan paling sering kamu pakai. useState gunanya buat menambahkan state ke Functional Component.

Cara pakainya gini:

jsx
import React, { useState } from 'react';function Counter() {
  // Deklarasi state 'count' dengan nilai awal 0
  const [count, setCount] = useState(0);return (
    
      Kamu klik sebanyak {count} kali
      {/ Ketika button diklik, panggil setCount untuk update state /}
       setCount(count + 1)}>
        Klik Aku
      
    
  );
}

Penjelasan:

  • useState(0): Kita manggil fungsi useState dan ngasih nilai awal 0 buat state kita.
  • const [count, setCount] = useState(0);: useState itu mengembalikan sepasang nilai (pakai array destructuring):

* Nilai pertama (count) adalah nilai state saat ini. * Nilai kedua (setCount) adalah sebuah fungsi yang bisa kamu pakai buat meng-update state tersebut.

  • Ketika setCount dipanggil, React akan nge-render ulang komponen Counter ini dengan nilai count yang baru.

Kamu bisa punya lebih dari satu state di komponen yang sama:

jsx
function ProfileEditor() {
  const [name, setName] = useState('Anonim');
  const [age, setAge] = useState(0);return (
    
      Nama: {name}
       setName(e.target.value)} />
      Umur: {age}
       setAge(parseInt(e.target.value))} />
    
  );
}

Simpel banget kan? Nggak perlu this.state atau this.setState({ ... }).

2. useEffect (Buat Ngurusin Side Effect)

Ingat masalah Lifecycle Methods di Class Component yang logic-nya kepisah-pisah? Nah, useEffect ini datang buat nyelesaiin itu. useEffect memungkinkan kamu ngelakuin side effect di Functional Component.

Side effect itu apa sih? Ya tadi, hal-hal yang terjadi di "samping" proses utama rendering, kayak:

  • Mengambil data dari API
  • Manipulasi DOM secara manual
  • Setup subscription atau event listener
  • Mengupdate judul halaman

useEffect menerima dua argumen:

  1. Sebuah fungsi yang berisi kode side effect-mu.
  2. Array dependencies (opsional tapi penting banget!).

Contoh paling umum: Mengambil data dari API pas komponen pertama kali muncul.

jsx
import React, { useState, useEffect } from 'react';function DataFetcher() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);useEffect(() => {
    // Fungsi side effect
    console.log("Efek dijalankan!");
    fetch('https://swapi.dev/api/people/1/') // Contoh API Star Wars
      .then(response => response.json())
      .then(result => {
        setData(result);
        setLoading(false);
      })
      .catch(error => {
        console.error("Error fetching data:", error);
        setLoading(false);
      });// Optional: Cleanup function
    return () => {
      console.log("Efek dibersihkan!");
      // Misalnya: cancel request, clear timer, remove event listener
    };}, []); // <-- Array dependency kosongif (loading) return Loading data...;
  if (!data) return Gagal memuat data.;return (
    
      Data Karakter Star Wars:
      Nama: {data.name}
      Tinggi: {data.height} cm
      {/ ... data lain /}
    
  );
}

Penjelasan useEffect di atas:

  • useEffect(() => { ... }, []);: Fungsi pertama adalah kode yang akan dijalankan. Array kedua adalah dependency list.
  • [] (Array kosong): Ini artinya efek ini hanya akan dijalankan sekali setelah komponen pertama kali di-render (sama kayak componentDidMount). Ini pola umum buat data fetching.
  • Kalau dependency array-nya dihilangkan sama sekali, efek akan dijalankan setiap kali komponen di-render ulang. Jarang dipakai, hati-hati infinite loop!
  • Kalau dependency array-nya berisi nilai (misalnya [userId]), efek akan dijalankan pertama kali di-render, dan setiap kali nilai userId berubah. (Sama kayak componentDidMount + componentDidUpdate untuk dependency tertentu).
  • Fungsi yang dikembalikan di dalam useEffect (yg ada return () => { ... }) itu namanya cleanup function. Ini dijalankan sebelum efek dijalankan kembali (jika dependencies berubah) atau ketika komponen akan di-unmount (hilang dari layar). Berguna banget buat membersihkan sesuatu biar nggak memory leak (misalnya clear timer, unsubscribe).

useEffect ini powerful banget, tapi juga butuh pemahaman soal dependency array. Ini sering jadi sumber bug kalau salah pakai. Tipsnya: Pastikan semua variabel atau fungsi dari scope luar komponen yang kamu gunakan di dalam useEffect (dan yang bisa berubah seiring waktu) itu dimasukkan ke dalam dependency array. Linter eslint-plugin-react-hooks bisa bantu banget buat ngecek ini.

3. useContext (Buat Akses Context)

React Context API itu cara buat nge-share data "global" (atau data yang sering dipake di banyak komponen) tanpa harus nge-passing props turun-temurun (props drilling). Dulu, akses context di Class Component pakai MyContext.consumer atau static contextType.

Dengan Hooks, akses context jadi lebih gampang pakai useContext.

jsx
// Buat Context-nya dulu (biasanya di file terpisah)
import React, { createContext } from 'react';export const ThemeContext = createContext('light'); // Nilai default 'light'// Komponen Provider (kasih nilai context ke bawahannya)
function App() {
  const [theme, setTheme] = useState('light');
  // ... render komponen lainreturn (
    
      {/ Komponen lain yang butuh theme /}
      
    
  );
}// Komponen yang mengakses Context pakai useContext
import React, { useContext } from 'react';
import { ThemeContext } from './ThemeContext'; // Import context yang tadi dibuatfunction ThemedButton() {
  const theme = useContext(ThemeContext); // Akses nilai theme dari context

Dengan useContext(MyContext), kamu langsung dapat nilai dari context tersebut, tanpa wrapper atau render props. Jauh lebih bersih!

4. useRef (Buat Referensi dan Nilai Mutable Non-State)

useRef punya dua kegunaan utama:

  • Mengambil referensi ke elemen DOM: Mirip kayak React.createRef() di Class Component. Berguna buat ngakses elemen DOM secara langsung, misalnya buat focus ke input.

Menyimpan nilai mutable yang tidak memicu re-render: Kalau kamu punya nilai yang berubah tapi kamu nggak mau* perubahan itu bikin komponen re-render, pakai useRef. Contohnya menyimpan ID timer, counter yang tidak ditampilkan, atau nilai sebelumnya dari state/props.

jsx
import React, { useRef, useEffect } from 'react';function FocusInput() {
  const inputRef = useRef(null); // useRef mengembalikan objek dengan properti .currentuseEffect(() => {
    // Akses elemen DOM lewat inputRef.current
    if (inputRef.current) {
      inputRef.current.focus(); // Set focus ke input pas komponen mount
    }
  }, []); // [] artinya efek dijalankan sekali saat mount// useRef juga bisa nyimpen nilai lain
  const renderCount = useRef(0);// Ini akan nambah setiap render, tapi nggak bikin komponen re-render lagi
  renderCount.current = renderCount.current + 1;
  console.log(Komponen dirender sebanyak ${renderCount.current} kali);return (
    
       {/ Hubungkan ref dengan elemen DOM /}
      Cek console log untuk hitungan render (renderCount.current: {renderCount.current}) {/ Nilai useRef nggak otomatis update di UI /}
    
  );
}

Perlu diingat, mengubah nilai current pada useRef tidak akan memicu re-render. Kalau kamu butuh nilai yang berubah dan perubahannya harus ditampilkan di UI, pakai useState.

5. useMemo dan useCallback (Buat Optimasi Performa)

Dua Hook ini sering dipakai buat optimasi performa dengan "memoization". Artinya, React akan "mengingat" hasil dari sebuah perhitungan (untuk useMemo) atau definisi sebuah fungsi (untuk useCallback), dan hanya akan menghitung ulang atau membuat ulang fungsi tersebut kalau dependencies-nya berubah.

useMemo: Memoize sebuah nilai*. Hindari perhitungan ulang yang mahal kalau dependencies nggak berubah.

jsx
    import React, { useMemo } from 'react';function MyComponent({ data }) {
      // Anggap calculateExpensiveValue ini fungsi yang butuh banyak waktu
      // Ini hanya akan dijalankan lagi kalau 'data' berubah
      const memoizedValue = useMemo(() => calculateExpensiveValue(data), [data]);return (
        
          Hasil perhitungan mahal: {memoizedValue}
          {/ ... render lain /}
        
      );
    }

useCallback: Memoize sebuah fungsi*. Pastikan fungsi yang kamu passing sebagai props ke komponen anak (terutama komponen anak yang di-memoize pakai React.memo) nggak dibuat ulang di setiap render kalau dependencies-nya nggak berubah. Ini penting biar komponen anak nggak ikut-ikutan re-render kalau props fungsinya nggak berubah.

jsx
    import React, { useState, useCallback } from 'react';
    import Button from './Button'; // Anggap ini komponen Button yang di-React.memofunction ParentComponent() {
      const [count, setCount] = useState(0);// Fungsi handleClick ini hanya akan dibuat ulang kalau 'count' berubah
      const handleClick = useCallback(() => {
        setCount(count + 1);
      }, [count]); // <-- Dependency array berisi 'count'return (
        
          Count: {count}
          {/ Button ini nggak akan re-render kalau handleClick nggak berubah /}
          Tambah
        
      );
    }

Penting diingat, useMemo dan useCallback jangan dipakai sembarangan. Pakai hanya kalau kamu benar-benar punya masalah performa dan yakin memoization adalah solusinya. Kadang, overhead (biaya) memoization itu sendiri bisa lebih mahal daripada perhitungan ulangnya.

6. Custom Hooks (Super Power Buat Re-use Logic!)

Ini adalah salah satu fitur Hooks yang paling keren. Kamu bisa bikin Hooks sendiri! Custom Hook hanyalah sebuah fungsi JavaScript yang namanya diawali dengan use (misalnya useFetch, useToggle, useLocalStorage) dan di dalamnya dia memanggil Hooks built-in lainnya (useState, useEffect, useContext, dll.).

Tujuannya? Meng-enkapsulasi logic stateful atau side effect yang sering dipakai dan bisa di-share antar komponen.

Contoh Custom Hook sederhana buat toggle boolean:

jsx
// useToggle.js
import { useState, useCallback } from 'react';function useToggle(initialValue = false) {
  const [value, setValue] = useState(initialValue);// Gunakan useCallback biar fungsi toggleValue nggak dibuat ulang terus
  const toggleValue = useCallback(() => {
    setValue(currentValue => !currentValue); // Pakai fungsi updater biar aman
  }, []); // <-- Dependency array kosong karena nggak pakai state/props dari luarreturn [value, toggleValue]; // Kembalikan state dan fungsi toggler
}export default useToggle;// Cara pakainya di komponen lain:
import React from 'react';
import useToggle from './useToggle'; // Import custom hookfunction MyComponent() {
  const [isModalOpen, toggleModal] = useToggle(false); // Pakai custom hook!return (
    
      
        {isModalOpen ? 'Tutup Modal' : 'Buka Modal'}
      
      {isModalOpen && (
        
          Konten Modal!
          Close
        
      )}
    
  );
}

Keren kan? Logic buat toggle boolean bisa dipake di mana aja cuma dengan manggil useToggle(). Ini bikin komponen jadi lebih fokus sama UI-nya, sementara logic-nya diurus sama Custom Hook.

Aturan Main (Rules of Hooks)

Ini penting banget! Ada dua aturan yang WAJIB kamu ikutin pas pakai Hooks:

  1. Hanya Panggil Hooks di Level Paling Atas (Top Level): Jangan panggil Hooks di dalam loop, di dalam kondisi (if), atau di dalam fungsi yang bersarang. Hooks harus dipanggil di level paling atas dari Functional Component atau Custom Hook-mu.
  2. Hanya Panggil Hooks dari Fungsi React: Hooks hanya boleh dipanggil dari Functional Component atau dari Custom Hook yang kamu buat sendiri. Kamu nggak boleh panggil Hooks dari Class Component biasa, atau dari fungsi JavaScript biasa.

Kenapa aturan ini penting? React mengandalkan urutan pemanggilan Hooks di setiap render untuk "mengingat" state atau efek mana yang berhubungan. Kalau urutannya berubah karena dipanggil di dalam kondisi atau loop, React bisa bingung dan error.

Tenang aja, React punya eslint-plugin-react-hooks yang bisa bantu ngecek apakah kamu udah ngikutin aturan ini. Install linter ini, hidupkan, dan dia akan ngasih tahu kalau ada aturan yang dilanggar.

Tips dan Best Practices Pakai Hooks

  • Install Linter: Udah disebutin tadi, install dan pakai eslint-plugin-react-hooks. Ini penyelamat banget!
  • Keep Hooks Simple: Kalau satu useEffect udah mulai terlalu kompleks (ngurusin banyak hal yang nggak berhubungan), mungkin saatnya dipecah jadi beberapa useEffect terpisah. Logic yang beda, useEffect-nya beda.
  • Pahami Dependency Array: Ini kunci useEffect. Jangan lupa dependency array, dan pastikan isinya benar. Kalau kamu butuh function di dependency array, bungkus pakai useCallback. Kalau butuh nilai hasil perhitungan di dependency array, bungkus pakai useMemo.
  • Nama State yang Jelas: Beri nama state dan setter-nya yang deskriptif, misalnya [isLoading, setIsLoading], [userData, setUserData], [errorMessage, setErrorMessage].
  • Pakai Fungsi Updater State untuk Update Berbasis Nilai Sebelumnya: Kalau update state-mu bergantung sama nilai state sebelumnya (misalnya nambahin counter: setCount(count + 1)), lebih aman pakai fungsi updater: setCount(prevCount => prevCount + 1). Ini mencegah masalah kalau update state-mu di-batch sama React.
  • Jangan Takut Bikin Custom Hooks: Kalau kamu nemu logic yang berulang di beberapa komponen, langsung kepikiran buat Custom Hook! Ini bikin kodenya DRY (Don't Repeat Yourself) dan gampang di-maintain.

Bedakan Kapan Pakai useState vs useRef: Pakai useState kalau perubahan nilai harus bikin komponen re-render. Pakai useRef kalau kamu cuma butuh "wadah" mutable yang nilainya bisa diakses/diubah tapi tidak* memicu re-render, atau buat ngakses DOM.

Masa Depan React (dengan Hooks)

React Hooks bukan cuma alternatif, tapi sudah jadi cara yang direkomendasikan buat nulis komponen baru di React. Tim React sendiri bilang mereka nggak berencana menghapus Class Component, tapi semua fitur baru di React akan dibangun di atas Hooks. Jadi, kalau kamu baru belajar React atau lagi nulis aplikasi baru, sangat disarankan untuk langsung pakai Functional Component dan Hooks.

Migrasi dari Class Component ke Functional Component + Hooks itu bisa dilakukan bertahap, nggak harus semua sekaligus. Kamu bisa mulai dari komponen kecil dulu.

Kesimpulan

React Hooks itu fungsi spesial yang nambahin kemampuan state dan side effect ke Functional Component. Mereka bikin kode React jadi lebih bersih, gampang dibaca, gampang di-re-use, dan nyelesaiin banyak masalah yang ada di Class Component (kayak this dan logic yang terpencar di Lifecycle Methods).

Hooks paling dasar yang perlu kamu kuasai adalah useState buat state dan useEffect buat side effect. Setelah itu, kenalan sama useContext, useRef, serta useMemo/useCallback buat optimasi. Dan yang paling powerful, belajar bikin Custom Hooks sendiri buat nge-share logic.

Dengan memahami dan menguasai Hooks, kamu bakal bisa nulis aplikasi React yang lebih efisien, mudah di-maintain, dan modern. Jadi, jangan ragu buat nyoba dan latihan pakai Hooks ya! Semangat ngoding!