Meningkatkan performance menggunakan useMemo dan useCallback


Ketika mengembangkan web dengan fitur yang kompleks, akan ada banyak perubahan state pada setiap komponen. Dalam penggunaan React, perubahan satu state bisa menyebabkan komponen lain ikut di-render ulang. Bayangkan jika ada satu komponen yang memiliki beban kerja berat, tetapi kita hanya ingin mengubah state pada komponen yang lebih ringan. Hal ini dapat menyebabkan komponen ringan tersebut juga terasa lambat. Untuk menghadapi situasi seperti ini, kita bisa memanfaatkan useMemo dan useCallback sesuai dengan kebutuhan.

useMemo vs useCallback

Baik, perbedaan mendasar antara useCallback dan useMemo dalam React adalah sebagai berikut

useCallback: Digunakan untuk mengoptimalkan performa dengan mengingat kembali (memorize) versi dari sebuah fungsi callback yang sama, sehingga fungsi tersebut tidak di-create ulang setiap kali komponen dirender ulang, kecuali jika dependensi berubah.

useMemo: Digunakan untuk mengoptimalkan performa dengan mengingat kembali (memorize) hasil dari ekspresi pemrograman (baik itu nilai dari sebuah komputasi atau sebuah objek) sehingga nilai tersebut tidak dihitung ulang setiap kali komponen dirender ulang, kecuali jika dependensi berubah.

yup, mungkin aga sedikit membingungkan, akan tetapi pada intinya useCallback mengingat kembali fungsi sedangkan useMemo mengingat kembali value dari fungsi apabila tidak ada perubahan terhadap depedensi

Contoh Penggunaan useMemo

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

function ExpensiveComputationComponent() {
  const [count, setCount] = useState(0);
  const [inputValue, setInputValue] = useState('');

  // Fungsi ini melakukan perhitungan yang berat
  const expensiveComputation = (num) => {
    console.log('Computing...');
    for (let i = 0; i < 1000000000; i++) {
  console.log(i)
} // Simulasi perhitungan berat
    return num * 2;
  };

  // Menggunakan useMemo untuk menghindari perhitungan ulang yang tidak perlu
  const computedValue = useMemo(() => {
    return expensiveComputation(count);
  }, [count]);

  return (
    <div>
      <h1>Count: {count}</h1>
      <h2>Computed Value: {computedValue}</h2>
      <button onClick={() => setCount(count + 1)}>Increment Count</button>
      <br />
      <input 
        type="text" 
        value={inputValue} 
        onChange={(e) => setInputValue(e.target.value)} 
        placeholder="Type something" 
      />
      <p>Input Value: {inputValue}</p>
    </div>
  );
}

export default ExpensiveComputationComponent;

Dalam contoh di atas:

  • expensiveComputation adalah fungsi yang melakukan perhitungan berat.
  • useMemo digunakan untuk mengoptimalkan perhitungan computedValue sehingga hanya dihitung ulang ketika count berubah.
  • Tanpa useMemo, expensiveComputation akan dipanggil setiap kali komponen dirender, termasuk saat inputValue berubah. Dengan useMemo, perhitungan hanya dilakukan saat count berubah, meningkatkan kinerja komponen.

Contoh Penggunaan useCallback

Penggunaan useCallback akan lebih powerfull jika dikombinasikan dengan React.memo

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

const Button = memo(({ onClick, children }) => {
  console.log(`Rendering button: ${children}`);
  return <button onClick={onClick}>{children}</button>;
});

function ParentComponent() {
  const [count, setCount] = useState(0);
  const [otherState, setOtherState] = useState(false);

  const increment = useCallback(() => {
    setCount(prevCount => prevCount + 1);
  }, []);

  const toggleOtherState = () => {
    setOtherState(prevState => !prevState);
  };

  return (
    <div>
      <h1>Count: {count}</h1>
      <Button onClick={increment}>Increment</Button>
      <button onClick={toggleOtherState}>Toggle Other State</button>
      <p>Other state: {otherState.toString()}</p>
    </div>
  );
}

export default ParentComponent;

Dalam contoh ini:

  • Komponen Button di-memoize menggunakan React.memo untuk mencegah render ulang yang tidak perlu.
  • increment di-memoize menggunakan useCallback sehingga fungsi yang sama akan digunakan kembali pada setiap render, kecuali jika dependensinya berubah.
  • Ketika otherState berubah, Button tidak akan dirender ulang karena increment tidak berubah.

Kesimpulan

Penggunaan useMemo dan useCallback sangat membantu dalam meningkatkan performa aplikasi dengan mengoptimalkan penggunaan sumber daya komputasi. Namun, tidak semua fungsi perlu diterapkan dengan kedua hooks tersebut. Penting untuk mempertimbangkan implementasi useMemo dan useCallback secara selektif, terutama untuk fungsi-fungsi yang memiliki biaya komputasi tinggi atau memori besar. Menggunakan kedua hooks secara berlebihan dapat menambah overhead yang tidak perlu, terutama jika fungsi tersebut jarang dipanggil atau tidak memerlukan pengoptimalan khusus.

Referensi :