Panduan Lengkap Hook di ReactJS

A
IQBAL FARHAN SYUHADA
14 Jun 2024

React Hook adalah fitur yang diperkenalkan di React 16.8 yang memungkinkan Anda menggunakan state dan fitur lain dari React tanpa menulis kelas. Hook membuat pengelolaan state dan side effects dalam komponen fungsional menjadi lebih mudah dan lebih intuitif.

Jenis-jenis Hook di React

Ada beberapa jenis Hook di React yang dibagi menjadi dua kategori utama: Basic Hook dan Additional Hook.

Basic Hook

  1. useState
  2. useEffect
  3. useContext

Additional Hook

  1. useReducer
  2. useCallback
  3. useMemo
  4. useRef
  5. useImperativeHandle
  6. useLayoutEffect
  7. useDebugValue

Mari kita bahas masing-masing Hook tersebut.

Basic Hook

1. useState

Hook useState memungkinkan Anda untuk menambahkan state lokal ke dalam komponen fungsional. Anda memanggilnya dalam fungsi komponen untuk menyimpan state.

import React, { useState } from 'react';

function Counter() {
  // Mendeklarasikan variabel state "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Anda telah mengklik {count} kali</p>
      <button onClick={() => setCount(count + 1)}>Klik saya</button>
    </div>
  );
}

2. useEffect

Hook useEffect memungkinkan Anda melakukan side effects dalam komponen fungsional. Side effects dapat berupa pengambilan data, manipulasi DOM, dan lainnya.

import React, { useState, useEffect } from 'react';

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

  useEffect(() => {
    document.title = `Anda telah mengklik ${count} kali`;
  }, [count]);

  return (
    <div>
      <p>Anda telah mengklik {count} kali</p>
      <button onClick={() => setCount(count + 1)}>Klik saya</button>
    </div>
  );
}

3. useContext

Hook useContext memungkinkan Anda untuk menggunakan konteks React tanpa harus menggunakan komponen kelas atau komponen tinggi (higher-order components).

import React, { useContext } from 'react';

const ThemeContext = React.createContext('light');

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar() {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return <button style={{ background: theme }}>Tema saya</button>;
}

Additional Hook

1. useReducer

Hook useReducer sering digunakan untuk mengelola state yang kompleks dan logika pembaruan yang terkait dengan state tersebut.

import React, { useReducer } from 'react';

const initialState = { count: 0 };

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
    </div>
  );
}

2. useCallback

Hook useCallback mengembalikan versi memoized dari callback yang hanya berubah jika salah satu dependensi telah berubah. Ini berguna untuk mengoptimalkan kinerja komponen anak yang bergantung pada callback.

import React, { useState, useCallback } from 'react';

function Parent() {
  const [count, setCount] = useState(0);
  const increment = useCallback(() => setCount(count + 1), [count]);

  return (
    <div>
      <Child increment={increment} />
    </div>
  );
}

function Child({ increment }) {
  console.log('Child render');
  return <button onClick={increment}>Increment</button>;
}

3. useMemo

Hook useMemo hanya menghitung ulang nilai memoized ketika salah satu dependensi telah berubah. Ini dapat digunakan untuk mengoptimalkan kinerja dengan menghindari perhitungan yang tidak perlu.

import React, { useState, useMemo } from 'react';

function ExpensiveCalculation({ num }) {
  const compute = (num) => {
    console.log('Calculating...');
    let result = 0;
    for (let i = 0; i < 1e6; i++) {
      result += num;
    }
    return result;
  };

  const memoizedValue = useMemo(() => compute(num), [num]);

  return <div>{memoizedValue}</div>;
}

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

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <ExpensiveCalculation num={count} />
    </div>
  );
}

4. useRef

Hook useRef dapat digunakan untuk menyimpan referensi mutable yang tidak menyebabkan re-render ketika berubah. Ini sering digunakan untuk mengakses elemen DOM secara langsung.

import React, { useRef } from 'react';

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    inputEl.current.focus();
  };

  return (
    <div>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus input</button>
    </div>
  );
}

5. useImperativeHandle

Hook useImperativeHandle dapat digunakan bersama dengan forwardRef untuk mengustomisasi nilai instance yang diekspos saat menggunakan referensi.

import React, { useRef, useImperativeHandle, forwardRef } from 'react';

const FancyInput = forwardRef((props, ref) => {
  const inputRef = useRef();

  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    },
  }));

  return <input ref={inputRef} />;
});

function App() {
  const fancyInputRef = useRef();

  return (
    <div>
      <FancyInput ref={fancyInputRef} />
      <button onClick={() => fancyInputRef.current.focus()}>Focus input</button>
    </div>
  );
}

6. useLayoutEffect

Hook useLayoutEffect memiliki signature yang sama dengan useEffect, tetapi dijalankan secara sinkron setelah semua mutasi DOM.

import React, { useLayoutEffect, useRef } from 'react';

function LayoutEffectExample() {
  const divRef = useRef();

  useLayoutEffect(() => {
    divRef.current.style.color = 'red';
  }, []);

  return <div ref={divRef}>Hello World</div>;
}

7. useDebugValue

Hook useDebugValue digunakan untuk menampilkan label debug untuk hook custom.

import React, { useState, useDebugValue } from 'react';

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

  // Kustomisasi label debug
  useDebugValue(isOnline ? 'Online' : 'Offline');

  // Logika hook...
  
  return isOnline;
}

Custom Hook

Anda juga dapat membuat hook custom untuk menyederhanakan kode yang berulang. Hook custom hanyalah fungsi JavaScript yang namanya dimulai dengan "use" dan dapat memanggil hook lain di dalamnya.

import { useState, useEffect } from 'react';

function useWindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);

  useEffect(() => {
    const handleResize = () => setWidth(window.innerWidth);
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return width;
}

function App() {
  const width = useWindowWidth();

  return (
    <div>
      <p>Window width: {width}</p>
    </div>
  );
}

Kesimpulan

React Hook memberikan cara yang kuat dan fleksibel untuk mengelola state dan side effects dalam komponen fungsional. Dengan memahami dan menguasai berbagai jenis hook yang disediakan oleh React, Anda dapat menulis kode yang lebih bersih, lebih modular, dan lebih mudah untuk dipelihara.