Pengenalan React Hooks

React Hooks adalah fitur baru yang diperkenalkan dalam React versi 16.8. Hooks memungkinkan pengembang untuk menggunakan state dan fitur React lainnya dalam komponen functional, yang sebelumnya hanya tersedia dalam komponen class. Ini adalah cara baru dan lebih sederhana untuk menulis komponen React tanpa menggunakan class.

Sebelum adanya Hooks, penggunaan state dan fitur lainnya dalam React terbatas pada komponen class. Namun, dengan semakin kompleksnya aplikasi React, penggunaan class component seringkali membuat kode menjadi rumit dan sulit dipelihara. Hooks diperkenalkan untuk mengatasi masalah ini dan memberikan alternatif yang lebih sederhana dan elegan dalam menulis komponen React.

Manfaat Penggunaan React Hooks:

  1. Sederhana dan Mudah Dipahami: Hooks menyederhanakan sintaks dan logika dalam penulisan komponen React, membuatnya lebih mudah dipahami oleh pengembang, terutama bagi mereka yang baru mempelajari React.

  2. Mengurangi Kode yang Berlebihan: Dengan menggunakan Hooks, kode menjadi lebih ringkas dan mudah dipelihara. Pengembang tidak perlu lagi menulis boilerplate code yang terkait dengan class component.

  3. Memisahkan Logika dari Tampilan: Dengan memisahkan logika komponen dari tampilan, Hooks memungkinkan pengembang untuk lebih fokus pada struktur aplikasi dan pengelolaan state.

  4. Meningkatkan Kinerja: Dibandingkan dengan class component, komponen functional dengan Hooks cenderung memiliki performa yang lebih baik karena overhead yang lebih rendah.

Mengenal useState Hook

useState adalah salah satu dari beberapa Hooks yang disediakan oleh React untuk mengelola state dalam komponen fungsi. Dengan menggunakan useState, kita bisa menambahkan state lokal ke dalam komponen fungsi tanpa perlu mengubahnya menjadi class component.

Selanjutnya kita persiapkan project kita, disini saya menggunakan setup project dari blog ini. Kemudian, buat file component StateComponent.jsx untuk mencoba useState Hook. Masukkan kode berikut pada StateComponent.jsx.

import React, { useState } from 'react';

export default function StateComponent() {
  const [count, setCount] = useState(0);
  const incrementCount = () => {
    setCount(count + 1);
  };
  return (
    <div>
      <p>Nilai count: {count}</p>
      <button type="button" onClick={incrementCount}>
        Tambah Count
      </button>
    </div>
  );
}

Dalam contoh di atas, kita menggunakan useState untuk menambahkan state 'count' dengan nilai awal 0. Kemudian, kita mendefinisikan fungsi 'incrementCount' yang akan dipanggil ketika tombol diklik, yang akan meningkatkan nilai count dengan 1 setiap kali dipanggil.

Dengan menggunakan useState Hook, pengelolaan state dalam komponen fungsi menjadi lebih mudah dan efektif, membantu kita dalam membangun aplikasi React yang lebih baik.

Mengenal useEffect Hook

useEffect adalah salah satu hooks yang paling sering digunakan dalam React. Hook ini memungkinkan kita untuk melakukan efek samping dalam komponen fungsi, seperti melakukan panggilan HTTP, consume data dari API, mengelola langganan, dan banyak lagi. useEffect dipanggil setiap kali komponen dirender, dan kita dapat mengontrol kapan efek tersebut dijalankan dengan menggunakan dependensi.

Untuk menggunakan useEffect, kita cukup mengimpor hook tersebut dari 'react' dan kemudian memanggilnya di dalam komponen kita. useEffect menerima dua parameter: sebuah fungsi efek yang akan dijalankan, dan sebuah array dependensi opsional yang menentukan kapan efek tersebut harus dijalankan.

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

export default function EffectComponent() {
  const [posts, setPosts] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(
          'https://jsonplaceholder.typicode.com/posts'
        );
        if (!response.ok) {
          throw new Error('Gagal memuat data');
        }
        const data = await response.json();
        setPosts(data);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, []);

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;
  return (
    <div>
      <h1>Data Posts</h1>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
}

Dalam contoh ini, kita menggunakan API JSONPlaceholder untuk mendapatkan daftar posting. Anda dapat mengakses data melalui URL https://jsonplaceholder.typicode.com/posts. Data yang diterima adalah dalam bentuk array objek, di mana setiap objek mewakili satu posting. Kita kemudian menggunakan useEffect untuk memuat data saat komponen dimount, dan menampilkan daftar posting tersebut dalam bentuk daftar ul.

Kapan Menggunakan useEffect?

Kita dapat menggunakan useEffect untuk berbagai hal, seperti:

  • Memuat data awal dari API.

  • Berlangganan dan membatalkan langganan dari WebSocket atau EventSource.

  • Melakukan manipulasi DOM setelah komponen dirender.

  • Menjalankan kode yang membutuhkan pembaruan setiap kali prop atau state berubah.

Contoh penerapan useEffect lainnya:

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

export default function CountComponent() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    if (count % 2 === 0) {
      console.log('UseEffect invoked');
    }
  }, [count]);

  const increment = () => {
    setCount((prevCount) => prevCount + 1);
  };

  const decrement = () => {
    setCount((prevCount) => prevCount - 1);
  };
  return (
    <div>
      <h1>Counter</h1>
      <button type="button" onClick={increment}>
        Increment
      </button>
      <button type="button" onClick={decrement}>
        Decrement
      </button>
      <p>Count: {count}</p>
      <p>Even Count: {count % 2 === 0 ? count : count - 1}</p>
    </div>
  );
}

Di dalam komponen ini, kita menggunakan Hook useState untuk membuat state bernama count, yang akan menyimpan nilai dari hitungan yang sedang dilakukan.

Kemudian, kita menggunakan Hook useEffect untuk melakukan sesuatu setiap kali nilai dari count adalah bilangan genap. Dalam kasus ini, kita hanya mencetak pesan 'UseEffect invoked' ke konsol setiap kali nilai count adalah bilangan genap.

Kemudian, terdapat dua fungsi lainnya: increment dan decrement. Fungsi increment akan menambah nilai count dengan menggunakan fungsi updater dari setCount, sedangkan fungsi decrement akan mengurangi nilai count.

Pada bagian JSX, terdapat elemen-elemen HTML yang menampilkan tombol untuk menambah dan mengurangi nilai count, serta dua elemen <p> yang menampilkan nilai count dan nilai evenCount. evenCount dihitung secara langsung dalam JSX dengan menggunakan ekspresi ternary {count % 2 === 0 ? count : count - 1}, yang menentukan apakah count adalah bilangan genap atau ganjil.

Mengenal useRef Hook

Dalam pengembangan aplikasi web dengan ReactJS, seringkali kita perlu berinteraksi langsung dengan elemen DOM, menyimpan referensi ke elemen tersebut, atau mengakses nilai dari elemen input. Di sinilah useRef Hook hadir sebagai solusi yang sangat berguna.

useRef adalah salah satu dari banyak hooks bawaan yang disediakan oleh React. useRef digunakan untuk membuat referensi mutable (yang dapat berubah) ke elemen DOM atau nilai lain dalam komponen React. Ini memungkinkan kita untuk memanipulasi elemen DOM langsung dan menyimpan data di antara re-render komponen tanpa memicu re-render ulang.

Mengapa Menggunakan useRef Hook?

  • Mengakses Elemen DOM: useRef memungkinkan kita untuk dengan mudah mengakses elemen DOM langsung dari komponen React.

  • Memelihara Nilai di antara Re-render: Kita dapat menggunakan useRef untuk menyimpan nilai yang tidak mempengaruhi re-render komponen.

  • Mengakses dan Memanipulasi Data: useRef memungkinkan kita untuk mengakses dan memanipulasi data di dalam komponen tanpa memicu re-rendering yang tidak perlu.

Misalkan kita ingin membuat sebuah fitur di mana ketika pengguna mengklik tombol, fokus otomatis akan beralih ke input teks. Berikut adalah contoh implementasinya:

import React, { useRef } from 'react';

export default function FocusComponent() {
  const inputRef = useRef(null);

  const handleClick = () => {
    inputRef.current.focus();
  };
  return (
    <div>
      <input type="text" ref={inputRef} />
      <button type="button" onClick={handleClick}>
        Focus Input
      </button>
    </div>
  );
}

Contoh sederhana lainnya seperti saat kita menggunakan useRef untuk memberikan fokus otomatis ke input teks saat halaman dimuat.

import React, { useRef } from 'react';

export default function FocusComponent() {
  const inputRef = useRef(null);

  const handleClick = () => {
    inputRef.current.focus();
  };
  return (
    <div>
      <input type="text" ref={inputRef} />
      <button type="button" onClick={handleClick}>
        Focus Input
      </button>
    </div>
  );
}

Mengenal useContext Hook

useContext adalah salah satu dari banyak Hooks yang disediakan oleh React untuk memungkinkan kita mengakses nilai dari Context dalam komponen fungsional tanpa perlu menuliskan Consumer.

Sebelum adanya useContext, untuk mengakses nilai dari Context dalam komponen fungsional, kita harus menggunakan Consumer, yang menyebabkan penulisan kode yang lebih panjang dan kurang intuitif. Dengan adanya useContext, kita dapat mengakses nilai dari Context secara langsung dalam komponen fungsional, membuat kode lebih singkat, bersih, dan mudah dipahami.

Manfaat Penggunaan useContext:

  • Mengurangi tingkat penanaman prop dan prop drilling.

  • Membuat kode lebih bersih, singkat, dan mudah dipahami.

  • Memisahkan kekhawatiran tentang state global dari komponen, meningkatkan modularitas dan skalabilitas kode.

Langsung ke project sederhana, disini kita akan membuat dan menampilkan postingan. Kita akan menggunakan useContext untuk mengelola state aplikasi, seperti daftar postingan.

  1. Buat folder context, kemudian buat file baru bernama PostContext.jsx. Di dalamnya, buatlah Context untuk mengelola state postingan seperti ini:

     import React, { createContext, useMemo, useState } from 'react';
     import PropTypes from 'prop-types';
    
     const PostContext = createContext();
    
     function PostProvider({ children }) {
       const [posts, setPosts] = useState([]);
    
       const addPost = (newPost) => {
         setPosts([...posts, newPost]);
       };
    
       const deletePost = (postId) => {
         setPosts(posts.filter((post) => post.id !== postId));
       };
    
       const contextValue = useMemo(() => ({ posts, addPost, deletePost }), [posts]);
    
       return (
         <PostContext.Provider value={contextValue}>
           {children}
         </PostContext.Provider>
       );
     }
    
     PostProvider.propTypes = {
       children: PropTypes.node.isRequired
     };
    
     export { PostProvider, PostContext };
    

    Penjelasan Kode:

    • Create PostContext: Pertama, kita membuat konteks baru menggunakan fungsi createContext() dengan variabel PostContext. Context ini berfungsi sebagai tempat penyimpanan nilai global yang dapat diakses oleh komponen-komponen di dalamnya.

    • PostProvider Component: Selanjutnya, kita memiliki komponen PostProvider, yang bertugas menyediakan nilai konteks kepada seluruh komponen yang berada di dalamnya. Di sini, kita menetapkan state dan logika terkait dengan konteks, seperti state posts dan fungsi-fungsi addPost dan deletePost.

    • useState Hooks: Dalam komponen PostProvider, kita menggunakan hook useState untuk mendefinisikan state posts. State ini akan digunakan untuk menyimpan daftar posting.

    • addPost Function: Fungsi ini bertanggung jawab untuk menambahkan posting baru ke dalam daftar posting. Ketika dipanggil, fungsi ini akan menambahkan posting baru ke dalam daftar dengan menggunakan spread operator untuk menggabungkan posting baru dengan daftar yang sudah ada.

    • deletePost Function: Fungsi ini digunakan untuk menghapus posting dari daftar berdasarkan ID posting. Dalam implementasinya, kita menggunakan metode filter() untuk membuat daftar posting baru yang tidak termasuk posting dengan ID yang diberikan.

    • useMemo Hook: Kita menggunakan hook useMemo untuk mengingat nilai konteks yang dihasilkan. Nilai ini hanya akan dihitung ulang saat nilai state posts berubah, sehingga membantu mengoptimalkan kinerja aplikasi.(useMemo akan di jelaskan dibawah)

    • Return Statement: Di dalam komponen PostProvider, kita mengembalikan PostContext.Provider dengan nilai konteks yang disediakan melalui properti value. Dengan cara ini, nilai posts, addPost, dan deletePost dapat diakses oleh semua komponen yang berlangganan konteks ini.

    • PropTypes: Penggunaan PropTypes bertujuan untuk mendefinisikan tipe properti yang diterima oleh PostProvider agar dapat digunakan sebagai panduan bagi pengembang yang menggunakan komponen ini.

    • Export PostProvider dan PostContext: Terakhir, kita mengekspor PostProvider dan PostContext agar bisa digunakan oleh komponen lain di dalam aplikasi React.

  2. Selanjutnya buat komponen PostComponent.jsx untuk menampilkan postingan.

     import React, { useContext } from 'react';
     import PropTypes from 'prop-types';
     import { PostContext } from '../context/PostContext';
    
     export default function PostComponent({ post }) {
       const { deletePost } = useContext(PostContext);
    
       const handleDelete = () => {
         deletePost(post.id);
       };
       return (
         <div>
           <h3>{post.title}</h3>
           <p>{post.body}</p>
           <button type="button" onClick={handleDelete}>
             Delete
           </button>
         </div>
       );
     }
    
     PostComponent.propTypes = {
       post: PropTypes.shape({
         id: PropTypes.number.isRequired,
         title: PropTypes.string.isRequired,
         body: PropTypes.string.isRequired,
       }).isRequired,
     };
    

    Penjelasan kode:

    • Import Statements: Kode ini dimulai dengan mengimpor React, useContext, dan PropTypes dari library props-types

    • , serta mengimpor PostContext dari file ../context/PostContext. Ini mengatur semua dependensi yang diperlukan untuk komponen PostComponent.

    • PostComponent Function: Ini adalah fungsi komponen utama yang bertanggung jawab untuk merender tampilan satu posting. Diberikan objek post sebagai properti, komponen ini akan merender judul dan konten posting, serta tombol untuk menghapus posting.

    • useContext Hook: Di dalam komponen, kita menggunakan hook useContext untuk mengakses nilai dari PostContext. Ini memungkinkan kita untuk mengakses fungsi deletePost yang disediakan oleh penyedia konteks dan menggunakannya untuk menghapus posting.

    • handleDelete Function: Ini adalah fungsi yang dipanggil ketika tombol hapus diklik. Ketika tombol tersebut diklik, fungsi handleDelete akan memanggil deletePost dari konteks dengan ID posting sebagai argumen, yang akan menghapus posting tersebut dari daftar posting.

    • Return Statement: Fungsi komponen mengembalikan elemen JSX yang merender judul dan konten posting, serta tombol hapus. Ketika tombol tersebut diklik, fungsi handleDelete akan dipanggil untuk menghapus posting.

    • PropTypes: Digunakan untuk menentukan tipe properti yang diterima oleh komponen PostComponent. Properti post harus berupa objek dengan properti id, title, dan body, yang semuanya harus ada dan memiliki tipe yang sesuai.

  3. Kemudian buat komponen PostFormComponent.jsx untuk menambahkan postingan baru.

     import React, { useContext, useState } from 'react';
     import { PostContext } from '../context/PostContext';
    
     export default function PostFormComponent() {
       const [title, setTitle] = useState('');
       const [body, setBody] = useState('');
       const { addPost } = useContext(PostContext);
    
       const handleSubmit = (e) => {
         e.preventDefault();
         const newPost = { title, body, id: Date.now() };
         addPost(newPost);
         setTitle('');
         setBody('');
       };
       return (
         <form onSubmit={handleSubmit}>
           <input
             type="text"
             placeholder="Title"
             value={title}
             onChange={(e) => setTitle(e.target.value)}
           />
           <textarea
             placeholder="Body"
             value={body}
             onChange={(e) => setBody(e.target.value)}
           />
           <button type="submit">Add Post</button>
         </form>
       );
     }
    

    Penjelasan Kode:

    • Import Statements: Kode dimulai dengan mengimpor React, useContext, dan useState dari library React. Selain itu, PostContext diimpor dari file ../context/PostContext. Ini menetapkan semua dependensi yang dibutuhkan untuk komponen PostFormComponent.

    • useState Hook: Dua state lokal, title dan body, dideklarasikan menggunakan useState. Mereka digunakan untuk melacak nilai judul dan konten posting yang dimasukkan oleh pengguna melalui formulir.

    • useContext Hook: Digunakan untuk mengakses nilai dari PostContext. Dengan ini, kita dapat mengakses fungsi addPost yang disediakan oleh penyedia konteks.

    • handleSubmit Function: Ini adalah fungsi yang dipanggil ketika formulir disubmit. Saat formulir disubmit, fungsi ini akan mengumpulkan nilai judul dan konten posting dari state lokal, membuat objek newPost dengan nilai tersebut bersama dengan ID yang dihasilkan oleh Date.now(), dan kemudian memanggil fungsi addPost dari konteks dengan objek newPost sebagai argumen. Setelah itu, state lokal untuk judul dan konten posting akan direset menjadi string kosong.

    • Return Statement: Fungsi komponen mengembalikan elemen JSX yang berisi formulir untuk membuat posting baru. Formulir ini memiliki input untuk judul, textarea untuk konten posting, dan tombol "Add Post" yang akan memicu fungsi handleSubmit saat diklik.

  4. Kemudian buat komponen PostListComponent.jsx untuk menamplikan list postingan.

     import React, { useContext, useState } from 'react';
     import { PostContext } from '../context/PostContext';
    
     export default function PostFormComponent() {
       const [title, setTitle] = useState('');
       const [body, setBody] = useState('');
       const { addPost } = useContext(PostContext);
    
       const handleSubmit = (e) => {
         e.preventDefault();
         const newPost = { title, body, id: Date.now() };
         addPost(newPost);
         setTitle('');
         setBody('');
       };
       return (
         <form onSubmit={handleSubmit}>
           <input
             type="text"
             placeholder="Title"
             value={title}
             onChange={(e) => setTitle(e.target.value)}
           />
           <textarea
             placeholder="Body"
             value={body}
             onChange={(e) => setBody(e.target.value)}
           />
           <button type="submit">Add Post</button>
         </form>
       );
     }
    

    Penjelasan Kode:

    • Import Statements: Kode dimulai dengan mengimpor React dan useContext dari pustaka React. Selain itu, PostContext diimpor dari file ../context/PostContext, dan PostComponent diimpor dari file ./PostComponent. Ini menetapkan semua dependensi yang dibutuhkan untuk komponen PostListComponent.

    • useContext Hook: Digunakan untuk mengakses nilai dari PostContext. Dengan ini, kita dapat mengakses daftar posting yang disediakan oleh penyedia konteks.

    • Return Statement: Fungsi komponen mengembalikan elemen JSX yang berisi daftar posting. Ini dilakukan dengan menggunakan metode map untuk menghasilkan elemen PostComponent untuk setiap posting dalam daftar posts. Setiap PostComponent menerima prop post yang berisi detail posting, serta prop key yang unik untuk membantu React dalam melakukan reconciling dan re-rendering komponen dengan efisien.

  5. Selanjutnya di App.jsx, kita akan menggunakan PostProvider yang sudah kita buat sebelumnya untuk menyediakan state postingan kepada semua komponen di dalam aplikasi.

     import React from 'react';
     import './App.css';
     import { PostProvider } from './context/PostContext';
     import PostFormComponent from './components/PostFormComponent';
     import PostListComponent from './components/PostListComponent';
    
     function App() {
       return (
         <PostProvider>
           <div>
             <h1>Postingan</h1>
             <PostFormComponent />
             <PostListComponent />
           </div>
         </PostProvider>
       );
     }
    
     export default App;
    

    Penjelasan Kode:

    • Import Statements: Kode dimulai dengan mengimpor React dan file CSS yang diperlukan untuk styling ('./App.css'). Selain itu, PostProvider diimpor dari file './context/PostContext', dan PostFormComponent serta PostListComponent diimpor dari file komponen masing-masing.

    • Elemen JSX: Di dalam fungsi komponen App, kita memiliki elemen JSX yang berisi elemen-elemen berikut:

      • <PostProvider>: Ini adalah komponen yang menyediakan konteks untuk komponen-komponen di dalamnya. Dengan menyediakan konteks, komponen-komponen di dalamnya dapat mengakses dan berbagi data tanpa harus melewatkan props secara langsung.

      • <div>: Ini adalah elemen div yang digunakan untuk merangkai elemen-elemen dalam aplikasi.

      • <h1>: Ini adalah elemen heading yang menampilkan judul aplikasi.

      • <PostFormComponent />: Ini adalah komponen yang digunakan untuk menampilkan formulir tambah posting.

      • <PostListComponent />: Ini adalah komponen yang digunakan untuk menampilkan daftar posting.

Mengenal useReducer Hook

useReducer adalah hooks yang mirip dengan useState, namun lebih kuat dan fleksibel untuk mengelola state dalam komponen fungsional. Dengan useReducer, kita dapat mengelola state yang lebih kompleks dan melakukan update state berdasarkan aksi tertentu.

Beberapa kelebihan penggunaan useReducer adalah:

  • Lebih cocok untuk mengelola state yang kompleks dan bergantung pada aksi tertentu.

  • Memisahkan logika state dari komponen, sehingga memudahkan untuk pengujian dan pemeliharaan.

  • Memungkinkan penggunaan context untuk berbagi state di antara komponen tanpa prop drilling.

Berikut adalah contoh aplikasi sederhana yang memungkinkan pengguna untuk menambah, menghapus, dan menyelesaikan tugas-tugas (todo).

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

const initialState = {
  todos: [],
};

const reducer = (state, action) => {
  switch (action.type) {
    case 'ADD_TODO':
      return {
        todos: [
          ...state.todos,
          { id: Date.now(), text: action.payload, completed: false },
        ],
      };
    case 'TOGGLE_TODO':
      return {
        todos: state.todos.map((todo) =>
          todo.id === action.payload
            ? { ...todo, completed: !todo.completed }
            : todo
        ),
      };
    case 'DELETE_TODO':
      return {
        todos: state.todos.filter((todo) => todo.id !== action.payload),
      };
    default:
      return state;
  }
};

export default function TodoComponent() {
  const [text, setText] = useState('');
  const [state, dispatch] = useReducer(reducer, initialState);

  const handleSubmit = (e) => {
    e.preventDefault();
    if (!text.trim()) return;
    dispatch({ type: 'ADD_TODO', payload: text });
    setText('');
  };
  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          value={text}
          onChange={(e) => setText(e.target.value)}
        />
        <button type="submit">Add Todo</button>
      </form>
      <ul>
        {state.todos.map((todo) => (
          <li key={todo.id}>
            <button type='button'
              style={{
                textDecoration: todo.completed ? 'line-through' : 'none',
              }}
              onClick={() =>
                dispatch({ type: 'TOGGLE_TODO', payload: todo.id })
              }
            >
              {todo.text}
            </button>
            <button type='button'
              onClick={() =>
                dispatch({ type: 'DELETE_TODO', payload: todo.id })
              }
            >
              Delete
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
}

Berikut penjelasan detailnya:

  1. initialState: Ini adalah objek yang berisi keadaan awal dari state kita. Dalam kasus ini, initialState hanya memiliki satu properti yaitu todos, yang merupakan array kosong yang akan menyimpan daftar tugas.

  2. reducer adalah sebuah fungsi yang mengelola perubahan state berdasarkan tindakan (action) yang diterima. Fungsi reducer menerima dua parameter, yaitu state saat ini dan action yang dijalankan. Berdasarkan jenis action, fungsi reducer akan mengembalikan state baru.

    Dalam fungsi reducer di atas, kita menentukan bagaimana state akan berubah berdasarkan jenis action yang diterima. Misalnya:

    • Saat jenis action adalah 'ADD_TODO', kita akan menambahkan sebuah todo baru ke dalam array todos.

    • Saat jenis action adalah 'TOGGLE_TODO', kita akan menandai sebuah todo sebagai selesai atau belum selesai.

    • Saat jenis action adalah 'DELETE_TODO', kita akan menghapus sebuah todo dari array todos.

Setiap kasus akan mengembalikan state baru yang sesuai dengan perubahan yang diinginkan, sementara kasus default akan mengembalikan state tanpa perubahan.

  1. Bagian TodoList adalah komponen utama yang bertanggung jawab untuk menampilkan daftar tugas (todos) dan mengelola interaksi pengguna terhadapnya. Berikut adalah penjelasan komponen TodoList:

    • useState: React hook useState digunakan untuk menyimpan state lokal pada komponen fungsional. Di sini, kita menggunakan useState untuk menyimpan nilai input pengguna yang merupakan teks untuk todo baru.

    • React hook useReducer digunakan untuk mengelola state aplikasi kompleks dengan menggunakan konsep reducer dan action. Di sini, kita menggunakan useReducer untuk mengelola daftar tugas (todos) dengan reducer yang telah didefinisikan sebelumnya.

    • handleSubmit: Ini adalah fungsi yang dipanggil saat pengguna mengirimkan formulir penambahan tugas. Fungsi ini membatalkan perilaku bawaan formulir (pengiriman ulang halaman) dan menambahkan tugas baru ke dalam daftar menggunakan action 'ADD_TODO'.

    • Di dalam elemen form, kita memiliki sebuah input teks yang akan digunakan pengguna untuk menambahkan tugas baru. Nilai input diatur oleh state text, dan setiap perubahan pada input akan memperbarui nilai text menggunakan setText.

    • Di bawahnya, kita memiliki elemen ul yang menampilkan daftar tugas. Setiap tugas dirender sebagai elemen li, dengan dua tombol yang memungkinkan pengguna untuk menandai tugas sebagai selesai (TOGGLE_TODO) atau menghapusnya (DELETE_TODO). Aksi ini dipicu oleh dispatch yang memicu action yang sesuai.

    • state.todos adalah array dari seluruh tugas yang disimpan dalam state. Setiap tugas dirender sebagai elemen li, dan dua tombol diberikan untuk setiap tugas untuk melakukan aksi sesuai dengan kebutuhan pengguna.

Mengenal useMemo Hook

useMemo adalah salah satu dari hooks yang disediakan oleh React untuk mengoptimalkan performa komponen dalam aplikasi React. Fungsi useMemo digunakan untuk memoisasi nilai yang dihitung secara komputasional sehingga nilai tersebut hanya dihitung ulang ketika dependensinya berubah.

Ketika menggunakan useMemo, Kita memberikan sebuah fungsi atau ekspresi yang akan dievaluasi, serta array dependencies yang menentukan kapan nilai tersebut harus dihitung ulang. Ketika salah satu nilai dalam array dependencies berubah, React akan menghitung kembali nilai dari fungsi atau ekspresi yang diberikan, dan memperbarui nilai memoized tersebut.

Penggunaan useMemo biasanya berguna dalam situasi di mana Anda memiliki perhitungan yang intensif secara komputasional atau ketika Anda ingin menghindari pengulangan perhitungan yang tidak perlu di setiap pembaharuan komponen. Dengan memanfaatkan useMemo, Anda dapat meningkatkan kinerja aplikasi Anda dengan mengoptimalkan proses perhitungan yang diperlukan.

Perbedaan antara useMemo, useState dan useEffect

useMemo, useState, dan useEffect adalah tiga hooks yang berbeda dalam React, dan masing-masing memiliki peran dan fungsi yang unik:

  1. useMemo:

    • useMemo digunakan untuk memoization nilai yang dihitung secara komputasional.

    • Ini berguna saat Anda ingin menghindari penghitungan yang mahal secara berulang kali dalam suatu komponen.

    • useMemo mengambil dua argumen: sebuah fungsi yang mengembalikan nilai yang ingin dimemoisasi, dan sebuah array dependencies yang menentukan kapan nilai memoized harus dihitung ulang.

    • Ini hanya menghitung ulang nilainya saat salah satu dependencies berubah.

    • Penggunaan useMemo berguna untuk mengoptimalkan kinerja komponen dengan menghindari perhitungan yang tidak perlu.

  2. useState:

    • useState digunakan untuk menyimpan dan mengelola state dalam komponen React.

    • Ini memungkinkan komponen untuk menyimpan dan memperbarui data secara lokal.

    • Setiap kali state berubah, komponen akan dirender ulang untuk mencerminkan perubahan tersebut.

    • Ini tidak memengaruhi kinerja secara langsung, tetapi digunakan untuk menyimpan data yang relevan dengan keadaan komponen.

  3. useEffect:

    • useEffect digunakan untuk melakukan efek samping di dalam komponen React.

    • Ini digunakan untuk melakukan tugas-tugas yang tidak mempengaruhi tampilan langsung, seperti berlangganan pada data eksternal, mengelola siklus hidup komponen, atau membersihkan sumber daya.

    • useEffect dapat digunakan untuk melakukan sesuatu setelah render komponen, dan dapat menerima dependencies yang akan memicu efek tersebut untuk dijalankan ulang ketika nilai dependencies berubah.

    • Ini memengaruhi kinerja jika efeknya mahal atau dilakukan secara berulang-ulang tanpa perlu.

Jadi, perbedaan utama antara useMemo, useState, dan useEffect adalah bahwa useMemo digunakan untuk memoization nilai yang dihitung secara komputasional, useState digunakan untuk mengelola state dalam komponen, dan useEffect digunakan untuk melakukan efek samping di dalam komponen. Semua tiga hooks ini memainkan peran yang berbeda dalam pengembangan aplikasi React dan digunakan untuk tujuan yang berbeda.

Kapan menggunakan useMemo

Berikut adalah beberapa kasus penggunaan useMemo dalam pembuatan web:

  1. Pengolahan Data atau Perhitungan yang Mahal: Misalnya, ketika Anda memiliki data yang besar atau perhitungan yang kompleks yang dilakukan dalam komponen, Anda dapat menggunakan useMemo untuk mememoize hasil perhitungan tersebut. Ini membantu menghindari perhitungan yang mahal setiap kali komponen dirender ulang.

  2. Pemanggilan API: Ketika Anda membuat pemanggilan API untuk mendapatkan data, Anda dapat menggunakan useMemo untuk mememoize hasil pemanggilan API tersebut. Ini memastikan bahwa pemanggilan API hanya dilakukan ketika dependensi (misalnya, prop atau state) yang berubah nilainya, dan memungkinkan kembali menggunakan hasil pemanggilan API yang dimemoize saat komponen dirender ulang.

  3. Penguraian String: Ketika Anda memiliki penguraian string yang kompleks atau operasi manipulasi string yang membutuhkan waktu lama, Anda dapat menggunakan useMemo untuk mememoize hasil penguraian string tersebut. Ini membantu menghindari penguraian string yang dilakukan setiap kali komponen dirender ulang.

  4. Komputasi Kompleks Lainnya: Ada banyak kasus di mana komputasi kompleks diperlukan dalam pembuatan web, seperti perhitungan matematis, pengolahan data, atau manipulasi struktur data. Dalam kasus-kasus ini, Anda dapat menggunakan useMemo untuk mememoize hasil komputasi tersebut dan mencegah perhitungan yang mahal setiap kali komponen dirender ulang.

Langsung saja ke contoh sederhana penggunaan useMemo, buat folder utils kemudian buat file math.js. isi seperti berikut:

export function factorial(n) {
  let result = 1;
  for (let i = 2; i <= n; i+=1) {
    result *= i;
  }
  return result;
}

export function permutation(totalItems, selectedItems) {
  return factorial(totalItems) / factorial(totalItems - selectedItems);
}

export function combination(totalItems, selectedItems) {
  return (
    factorial(totalItems) /
    (factorial(selectedItems) * factorial(totalItems - selectedItems))
  );
}

Buat file MemoComponent.jsx, kemudian isi seperti ini

import React, { useMemo, useState } from 'react';
import { combination, permutation } from '../utils/math';

export default function MemoComponent() {
  const [totalItems, setTotalItems] = useState(0);
  const [selectedItems, setSelectedItems] = useState(0);

  const permutationResult = useMemo(() => {
    console.log('Menghitung permutasi...');
    return permutation(totalItems, selectedItems);
  }, [totalItems, selectedItems]);

  const combinationResult = useMemo(() => {
    console.log('Menghitung kombinasi...');
    return combination(totalItems, selectedItems);
  }, [totalItems, selectedItems]);

  return (
    <div>
      <h1>Contoh Penggunaan useMemo di React</h1>
      <p>Masukkan jumlah total item:</p>
      <input
        type="number"
        value={totalItems}
        onChange={(e) => setTotalItems(parseInt(e.target.value, 10))}
      />
      <p>Masukkan jumlah item yang dipilih:</p>
      <input
        type="number"
        value={selectedItems}
        onChange={(e) => setSelectedItems(parseInt(e.target.value, 10))}
      />
      <p>Permutasi: {permutationResult}</p>
      <p>Kombinasi: {combinationResult}</p>
    </div>
  );
}

Penjelasan kode :

  1. import React, { useMemo, useState } from 'react';: Baris ini mengimpor React dan hooks useMemo dan useState dari pustaka React. Hooks digunakan untuk mengelola state dan efek samping di dalam functional component.

  2. import { combination, permutation } from '../utils/math';: Baris ini mengimpor fungsi combination dan permutation dari file math.js yang terletak di dalam folder utils. File math.js mungkin berisi definisi fungsi-fungsi matematika seperti permutasi, kombinasi, dll.

  3. export default function MemoComponent() { ... }: Ini adalah deklarasi dari functional component bernama MemoComponent. Component ini menangani logika dan tampilan terkait permutasi dan kombinasi.

  4. const [totalItems, setTotalItems] = useState(0); dan const [selectedItems, setSelectedItems] = useState(0);: Dua state totalItems dan selectedItems digunakan untuk menyimpan jumlah total item dan jumlah item yang dipilih. Mereka diinisialisasi dengan nilai awal 0 menggunakan useState hook.

  5. const permutationResult = useMemo(() => { ... }, [totalItems, selectedItems]);: Ini adalah penggunaan hook useMemo. Hook ini menghitung nilai permutasi hanya ketika nilai dari totalItems atau selectedItems berubah. Hasil perhitungan disimpan dalam variabel permutationResult.

  6. const combinationResult = useMemo(() => { ... }, [totalItems, selectedItems]);: Sama seperti penggunaan useMemo sebelumnya, hook ini digunakan untuk menghitung nilai kombinasi hanya ketika nilai dari totalItems atau selectedItems berubah. Hasil perhitungan disimpan dalam variabel combinationResult.

  7. Di dalam render function, terdapat elemen <input> untuk memasukkan jumlah total item dan jumlah item yang dipilih. Fungsi setTotalItems dan setSelectedItems digunakan untuk mengubah nilai state totalItems dan selectedItems ketika nilai input berubah.

  8. Terakhir, hasil perhitungan permutasi dan kombinasi ditampilkan di dalam elemen <p>.

Dengan menggunakan useMemo, perhitungan permutasi dan kombinasi hanya dilakukan jika ada perubahan nilai totalItems atau selectedItems, sehingga meningkatkan kinerja aplikasi.

Mengenal useCallback Hook

useCallback adalah salah satu dari banyak Hooks yang disediakan oleh React untuk mengelola state dan efek samping dalam komponen fungsional. Tujuan utama useCallback adalah untuk mengoptimalkan performa aplikasi React dengan memori caching dan menghindari pembuatan ulang fungsi yang sama setiap kali komponen dirender ulang.

Dalam konteks penggunaan, useCallback digunakan untuk menghindari pembuatan ulang fungsi yang ditentukan setiap kali komponen dirender ulang. Misalnya, dalam sebuah komponen, kita mungkin memiliki fungsi yang dilewatkan sebagai prop ke komponen turunan. Tanpa useCallback, setiap kali komponen induk dirender ulang, fungsi tersebut akan dibuat ulang, bahkan jika prop yang dilewatkan ke komponen turunan tetap sama. Hal ini dapat menyebabkan overhead yang tidak perlu dan mengurangi performa aplikasi.

Dengan menggunakan useCallback, kita dapat memastikan bahwa fungsi tersebut hanya dibuat ulang jika dependensi yang ditentukan berubah. Dengan demikian, kita dapat menghindari pembuatan ulang fungsi yang tidak perlu dan meningkatkan performa aplikasi secara keseluruhan.

Perbedaan useCallback dan useMemo:

Meskipun keduanya (useCallback dan useMemo) memiliki tujuan untuk mengoptimalkan performa dalam aplikasi React dengan menghindari pembuatan ulang nilai, mereka memiliki perbedaan dalam cara mereka bekerja dan kapan sebaiknya digunakan.

  1. useCallback:

    • useCallback digunakan untuk menghindari pembuatan ulang fungsi yang sama setiap kali komponen dirender ulang.

    • Ini mengambil dua argumen: fungsi yang akan dikelola dan array dependensi.

    • Ketika salah satu dependensi dalam array berubah nilainya, fungsi akan dibuat ulang. Jika tidak ada dependensi yang berubah, versi yang di-memoized dari fungsi akan digunakan kembali.

    • Biasanya digunakan untuk menghindari pembuatan ulang prop berupa fungsi yang dilewatkan ke komponen turunan.

  2. useMemo:

    • useMemo digunakan untuk menghindari pembuatan ulang nilai yang dihitung secara terkait dengan render komponen.

    • Ini mengambil dua argumen: sebuah fungsi yang mengembalikan nilai yang akan dimemoize, dan sebuah array dependensi.

    • Nilai yang dihitung akan dimemoize dan hanya dihitung ulang jika salah satu dependensi dalam array berubah nilainya.

    • Biasanya digunakan untuk menghindari pembuatan ulang nilai yang dihitung, seperti komputasi yang mahal, penguraian string, atau pemanggilan API.

Jadi, perbedaan utama antara useCallback dan useMemo adalah dalam cara mereka digunakan: useCallback untuk fungsi dan useMemo untuk nilai yang dihitung.

Selanjutnya berikut contoh sederhana penggunaan useCallback, pertama buat file ChildComponent.jsx, kemudian isi seperti berikut:

import React from 'react'
import PropTypes from 'prop-types';

export default function ChildComponent({increment}) {
  return (
    <div>
      <h2>Child Component</h2>
      <button type='button' onClick={increment}>Increment Count from Child</button>
    </div>
  );
}
ChildComponent.propTypes = {
  increment: PropTypes.func.isRequired
};

Penjelasan kode:

  • Import React and PropTypes: Kita mengimpor React dan PropTypes untuk membuat dan memvalidasi komponen React.

  • Functional Component: ChildComponent adalah komponen fungsional yang sederhana. Ini menerima satu prop bernama increment.

  • Rendering: Di dalam ChildComponent, kita merender sebuah elemen div yang berisi judul h2 dan sebuah tombol.

  • onClick Event: Saat tombol diklik, fungsi increment yang diterima dari komponen induk (parent) akan dipanggil.

  • PropTypes: Properti increment harus berupa sebuah fungsi, dan itu merupakan hal yang wajib (required) untuk digunakan. PropTypes digunakan untuk memastikan tipe data yang diterima oleh properti sesuai dengan yang diharapkan.

Kemudian buat file ParentComponent.jsx, dan isi seperti berikut :

import React, { useCallback, useState } from 'react';
import ChildComponent from './ChildComponent';

export default function ParentComponent() {
  const [count, setCount] = useState(0);

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

  return (
    <div>
      <h2>Parent Component</h2>
      <p>Count: {count}</p>
      <button type="button" onClick={incrementCount}>
        Increment Count
      </button>
      <ChildComponent increment={incrementCount} />
    </div>
  );
}
  1. import React, { useCallback, useState } from 'react';: Kode ini mengimpor modul React serta hooks useCallback dan useState dari pustaka React.

  2. export default function ParentComponent() { ... }: Ini adalah deklarasi dari komponen ParentComponent yang akan diekspor untuk digunakan di tempat lain dalam aplikasi.

  3. const [count, setCount] = useState(0);: Ini adalah pemanggilan useState hook untuk membuat state count dan fungsi setCount yang akan digunakan untuk mengelola nilai count. Nilai awal dari count adalah 0.

  4. const incrementCount = useCallback(() => { ... }, []);: Ini adalah pemanggilan useCallback hook. Di dalamnya, kita mendefinisikan fungsi incrementCount yang bertugas untuk meningkatkan nilai count setiap kali dipanggil. Karena dependensi kosong ([]), fungsi ini tidak akan di-recreated ketika komponen di-render ulang.

  5. <button type="button" onClick={incrementCount}>Increment Count</button>: Ini adalah tombol yang ketika diklik akan memanggil fungsi incrementCount yang telah didefinisikan sebelumnya. Dengan demikian, ketika tombol ini diklik, nilai count akan bertambah.

  6. <ChildComponent increment={incrementCount} />: Ini adalah pemanggilan komponen ChildComponent yang telah dibuat sebelumnya. Properti increment dilewatkan ke ChildComponent, yang nilainya adalah referensi ke fungsi incrementCount. Ini memungkinkan ChildComponent untuk menggunakan fungsi tersebut untuk melakukan peningkatan count di dalamnya.

Dengan menggunakan useCallback, kita memastikan bahwa fungsi incrementCount tidak akan di-recreated setiap kali komponen ParentComponent di-render ulang, yang dapat mengoptimalkan performa aplikasi.

Kasus lain, misalkan kita memiliki aplikasi React yang menampilkan daftar item yang dapat diperbarui secara dinamis. Setiap item memiliki tombol untuk menghapusnya dari daftar. Saat tombol hapus ditekan, kita perlu memperbarui daftar dengan item yang dihapus.

Jika kita membuat fungsi penghapus item di setiap iterasi daftar, setiap kali daftar diperbarui, fungsi-fungsi tersebut akan dibuat kembali. Ini dapat menyebabkan kinerja yang buruk jika daftar memiliki banyak item.

Kita dapat menggunakan useCallback untuk menyimpan referensi ke fungsi penghapus item, sehingga fungsi tersebut tidak dibuat ulang setiap kali komponen di-render ulang. contohnya kita bisa buat ItemComponent.jsx dan ItemListComponent.jsx

Link Repository untuk blog ini :

https://github.com/arief2020/blog-introduction-reactHook

Kesimpulan

Dalam blog "Pengenalan React Hooks", kita telah mempelajari berbagai hooks yang tersedia dalam React. Berikut adalah kesimpulan dari materi yang telah dibahas:

  1. useState: Hooks ini memungkinkan kita untuk menggunakan state dalam komponen functional. Kita dapat menyimpan dan memperbarui nilai state serta mengaksesnya dalam komponen tanpa perlu menggunakan class.

  2. useEffect: Digunakan untuk menangani efek samping dalam komponen React, seperti melakukan pembaruan DOM, berlangganan data, atau membersihkan sumber daya. Kita dapat menggunakan useEffect untuk menjalankan kode setelah setiap render atau untuk mengatur "efek samping" yang bergantung pada perubahan state atau props.

  3. useContext: Hooks ini memungkinkan kita untuk mengakses konteks (context) dalam komponen functional. Dengan useContext, kita dapat menghindari prop drilling dan dengan mudah mengambil nilai dari konteks induk.

  4. useReducer: Mirip dengan useState, tetapi lebih cocok untuk mengelola state yang lebih kompleks atau dalam kasus di mana perubahan state bergantung pada state sebelumnya atau aksi yang dikirimkan. Penggunaan useReducer dapat membuat kode lebih terstruktur dan mudah dipahami dalam kasus-kasus tertentu.

  5. useMemo: Hooks ini digunakan untuk mengoptimalkan kinerja dengan menyimpan nilai yang dihitung secara berulang-ulang. Kita dapat menggunakan useMemo untuk menghindari perhitungan yang mahal secara komputasi di setiap render.

  6. useCallback: Digunakan untuk menghindari pembuatan ulang fungsi yang sama di setiap render. Ini berguna ketika kita ingin mencegah perubahan tidak perlu pada props turun ke komponen yang bergantung pada referensi fungsi yang stabil.

Dengan memahami dan menggunakan berbagai hooks ini, kita dapat meningkatkan efisiensi, kinerja, dan keterbacaan kode dalam pengembangan aplikasi React. Dengan kemampuan untuk menggunakan state dan fitur-fitur React lainnya dalam komponen functional, React Hooks membuka banyak kemungkinan baru dalam pengembangan aplikasi front-end modern.