React JS

Menguasai Siklus Hidup Komponen React: Dari Lifecycle Methods Klasik Hingga Hooks Modern

Siklus Hidup Komponen React: Hooks vs Lifecycle Methods

PPLG

PPLG

Penulis

04 May 2026
1 x dilihat

Memahami Jantung Komponen React: Siklus Hidup

Dalam ekosistem React, siklus hidup sebuah komponen adalah serangkaian tahapan yang dilaluinya sejak ia dibuat, diperbarui, hingga akhirnya dihapus dari DOM. Memahami siklus hidup ini krusial untuk mengelola state, efek samping (seperti fetch data, subscriptions), dan optimasi performa secara efisien.

React menyediakan mekanisme untuk berinteraksi dengan siklus hidup ini, baik melalui Lifecycle Methods pada komponen kelas (Class Components) maupun melalui Hooks pada komponen fungsional (Functional Components). Artikel ini akan memandu Anda melalui kedua pendekatan tersebut, dari konsep dasar hingga implementasi praktis.

Komponen Kelas (Class Components) dan Lifecycle Methods

Sebelum era Hooks, komponen kelas adalah cara utama untuk membuat komponen yang memiliki state dan lifecycle. Lifecycle Methods adalah fungsi khusus yang dipanggil React pada waktu-waktu tertentu selama siklus hidup komponen.

Mari kita tinjau beberapa Lifecycle Methods yang paling umum digunakan:

  • constructor(props):

    • Dipanggil sebelum komponen di-mount.
    • Biasanya digunakan untuk menginisialisasi state lokal dan binding method.
    • Penting: Selalu panggil super(props) di awal constructor.
    class Counter extends React.Component {
      constructor(props) {
        super(props);
        this.state = { count: 0 };
        this.increment = this.increment.bind(this); // Binding method
      }
    
      increment() {
        this.setState({ count: this.state.count + 1 });
      }
    
      render() {
        return (
          <div>
            <p>Count: {this.state.count}</p>
            <button onClick={this.increment}>Increment</button>
          </div>
        );
      }
    }
    
  • render():

    • Metode paling penting dalam sebuah komponen.
    • Bertanggung jawab untuk mengembalikan elemen React yang akan dirender ke DOM.
    • Harus berupa fungsi murni (pure function) yang tidak memodifikasi state atau berinteraksi langsung dengan DOM.
  • componentDidMount():

    • Dipanggil segera setelah komponen di-mount (disisipkan ke DOM).
    • Tempat yang ideal untuk melakukan side effects seperti:
      • Fetch data dari API.
      • Mengatur subscriptions (misalnya, event listener).
      • Menginisialisasi library pihak ketiga.
    class UserProfile extends React.Component {
      state = { user: null };
    
      async componentDidMount() {
        const response = await fetch('/api/user/1');
        const user = await response.json();
        this.setState({ user });
      }
    
      render() {
        return (
          <div>
            {this.state.user ? (
              <p>Welcome, {this.state.user.name}</p>
            ) : (
              <p>Loading profile...</p>
            )}
          </div>
        );
      }
    }
    
  • componentDidUpdate(prevProps, prevState):

    • Dipanggil setelah komponen diperbarui (baik karena perubahan props atau state).
    • Berguna untuk melakukan aksi setelah update, misalnya:
      • Membandingkan prevProps atau prevState untuk mencegah infinite loop.
      • Melakukan fetch data lagi jika ada perubahan pada props tertentu.
    class SearchResults extends React.Component {
      state = { results: [] };
    
      async fetchResults(query) {
        const response = await fetch(`/api/search?q=${query}`);
        const results = await response.json();
        this.setState({ results });
      }
    
      componentDidMount() {
        this.fetchResults(this.props.query);
      }
    
      componentDidUpdate(prevProps) {
        if (this.props.query !== prevProps.query) {
          this.fetchResults(this.props.query);
        }
      }
    
      render() {
        return (
          <ul>
            {this.state.results.map(item => <li key={item.id}>{item.title}</li>)}
          </ul>
        );
      }
    }
    
  • componentWillUnmount():

    • Dipanggil tepat sebelum komponen dihapus dari DOM.
    • Tempat yang tepat untuk membersihkan side effects yang tidak lagi dibutuhkan, seperti:
      • Membatalkan fetch request yang sedang berjalan.
      • Menghapus event listeners.
      • Menghentikan subscriptions.
    • Penting: Mencegah memory leaks.
    class Timer extends React.Component {
      componentDidMount() {
        this.intervalId = setInterval(() => {
          console.log('Tick');
        }, 1000);
      }
    
      componentWillUnmount() {
        clearInterval(this.intervalId); // Membersihkan interval
        console.log('Timer stopped');
      }
    
      render() {
        return <p>Timer is running...</p>;
      }
    }
    

Komponen Fungsional (Functional Components) dan Hooks

Dengan diperkenalkannya Hooks di React 16.8, komponen fungsional kini dapat memiliki state dan mengelola lifecycle, menggantikan banyak dari kegunaan komponen kelas. Hooks memungkinkan Anda "mengaitkan" state dan fitur React lainnya ke komponen fungsional.

  • useState:

    • Hook untuk menambahkan state ke komponen fungsional.
    • Mengembalikan state value dan fungsi setter untuk memperbarui state tersebut.
    import React, { useState } from 'react';
    
    function CounterFunctional() {
      const [count, setCount] = useState(0); // State: count, Setter: setCount
    
      return (
        <div>
          <p>Count: {count}</p>
          <button onClick={() => setCount(count + 1)}>Increment</button>
        </div>
      );
    }
    
  • useEffect:

    • Hook yang menggabungkan componentDidMount, componentDidUpdate, dan componentWillUnmount ke dalam satu API.
    • Digunakan untuk melakukan side effects.
    • Menerima callback function yang akan dijalankan setelah render.
    • Memiliki array dependensi opsional di argumen kedua:
      • Array kosong []: Efek hanya dijalankan sekali setelah render pertama (mirip componentDidMount).
      • Array dengan variabel [var1, var2]: Efek dijalankan setelah render pertama, dan setiap kali var1 atau var2 berubah (mirip componentDidUpdate).
      • Tanpa array dependensi: Efek dijalankan setelah setiap render (jarang digunakan, bisa menyebabkan infinite loop jika tidak hati-hati).
    • Callback function bisa mengembalikan fungsi cleanup (mirip componentWillUnmount).
    import React, { useState, useEffect } from 'react';
    
    function UserProfileFunctional({ userId }) {
      const [user, setUser] = useState(null);
      const [loading, setLoading] = useState(true);
    
      useEffect(() => {
        // Simulates fetching data
        setLoading(true);
        const fetchUser = async () => {
          try {
            const response = await fetch(`/api/user/${userId}`);
            const data = await response.json();
            setUser(data);
          } catch (error) {
            console.error("Error fetching user:", error);
          } finally {
            setLoading(false);
          }
        };
    
        fetchUser();
    
        // Cleanup function (optional)
        return () => {
          console.log('UserProfile component unmounting or userId changed');
          // Cancel any ongoing fetch requests if possible
        };
      }, [userId]); // Dependency array: fetch data again if userId changes
    
      if (loading) {
        return <p>Loading profile...</p>;
      }
    
      return (
        <div>
          {user ? (
            <p>Welcome, {user.name}</p>
          ) : (
            <p>User not found.</p>
          )}
        </div>
      );
    }
    

    Contoh useEffect untuk timer (mirip componentDidMount + componentWillUnmount):

    import React, { useEffect } from 'react';
    
    function TimerFunctional() {
      useEffect(() => {
        const intervalId = setInterval(() => {
          console.log('Tick');
        }, 1000);
    
        // Cleanup: Stop the interval when the component unmounts
        return () => {
          clearInterval(intervalId);
          console.log('Timer stopped');
        };
      }, []); // Empty dependency array means this effect runs once on mount and cleans up on unmount
    
      return <p>Timer is running...</p>;
    }
    

Kapan Menggunakan yang Mana?

  • Hooks adalah masa depan React. Untuk semua komponen baru, sangat disarankan menggunakan komponen fungsional dengan Hooks. Hooks membuat kode lebih ringkas, mudah dibaca, dan memfasilitasi reuse logic.
  • Lifecycle Methods masih relevan untuk kode yang sudah ada. Jika Anda bekerja pada codebase yang menggunakan komponen kelas, Anda masih perlu memahami lifecycle methods.
  • Anda dapat mencampur keduanya. Dalam proyek yang sama, Anda dapat memiliki komponen kelas dan fungsional.

Tips Praktis yang Jarang Diketahui Pemula

  1. Menghindari Infinite Loops dengan useEffect: Selalu perhatikan dependency array useEffect. Jika Anda memperbarui state di dalam useEffect yang sama dan state tersebut menjadi dependensi, Anda akan menciptakan infinite loop. Pastikan hanya memasukkan variabel yang sebenarnya dibutuhkan oleh efek tersebut.
  2. setState Bersifat Asynchronous: Ketika Anda memanggil this.setState() di komponen kelas, perubahan state tidak langsung diterapkan. Jika Anda perlu melakukan sesuatu setelah state diperbarui, gunakan callback function dari setState atau metode componentDidUpdate.
    // Komponen Kelas
    this.setState({ count: this.state.count + 1 }, () => {
      console.log('State count updated to:', this.state.count); // Ini akan berjalan setelah update
    });
    
  3. useEffect dengan Fungsi Asynchronous Langsung: Anda tidak bisa langsung menggunakan async/await di dalam callback useEffect. React mengharapkan fungsi synchronous atau fungsi yang mengembalikan cleanup function.
    // SALAH
    // useEffect(async () => {
    //   const data = await fetchData();
    //   // ...
    // }, []);
    
    // BENAR
    useEffect(() => {
      const fetchData = async () => {
        const data = await fetch('/api/data');
        // ...
      };
      fetchData(); // Panggil fungsi async di dalam callback
    }, []);
    
  4. Conditional Fetching dengan useEffect: Gunakan dependency array untuk mengontrol kapan fetch data dilakukan. Misalnya, hanya fetch data pengguna jika userId valid.
    useEffect(() => {
      if (userId) {
        fetchUser(userId);
      }
    }, [userId]); // Fetch ulang hanya jika userId berubah
    
  5. Membatalkan Fetch Request di componentWillUnmount / useEffect Cleanup: Ini adalah praktik penting untuk mencegah pembaruan state pada komponen yang sudah di-unmount, yang dapat menyebabkan error. Gunakan AbortController untuk request fetch modern.
    useEffect(() => {
      const controller = new AbortController();
      const signal = controller.signal;
    
      const fetchData = async () => {
        try {
          const response = await fetch('/api/long-operation', { signal });
          const data = await response.json();
          // Update state...
        } catch (error) {
          if (error.name === 'AbortError') {
            console.log('Fetch aborted');
          } else {
            console.error('Fetch error:', error);
          }
        }
      };
    
      fetchData();
    
      return () => {
        controller.abort(); // Abort fetch when component unmounts or effect re-runs
      };
    }, []);
    
  6. Keamanan State Awal useState: State awal untuk useState bisa berupa nilai primitif, objek, atau bahkan fungsi yang mengembalikan nilai awal. Jika inisialisasi state membutuhkan kalkulasi yang intensif, berikan fungsi tersebut agar React hanya memanggilnya sekali saat inisialisasi pertama.
    const [complexState, setComplexState] = useState(() => {
      // Lakukan kalkulasi berat di sini
      return calculateInitialComplexState();
    });
    

Kesimpulan

Menguasai siklus hidup komponen, baik melalui Lifecycle Methods klasik maupun Hooks modern, adalah fondasi penting dalam membangun aplikasi React yang kuat dan efisien. Hooks telah membawa penyederhanaan dan kekuatan baru ke dalam komponen fungsional, menjadikannya pilihan utama untuk pengembangan React saat ini. Dengan pemahaman yang baik tentang kapan dan bagaimana menggunakan useEffect, useState, dan mensikapi side effects, Anda dapat membangun antarmuka pengguna yang responsif, terkelola dengan baik, dan bebas dari masalah umum seperti memory leaks. Teruslah bereksperimen dan membangun!

0.0

Berikan Rating

Komentar (0)

Silakan login untuk memberikan komentar.

Login Sekarang

Belum ada komentar. Jadilah yang pertama!

Pembaca (0)

Belum ada user yang membaca artikel ini.