ReactJS #21: useContext – Berbagi Data ke Semua Komponen Tanpa Ribet


ReactJS #21: useContext

Berbagi Data ke Semua Komponen Tanpa Ribet
(Seperti Pengeras Suara)

Halo, penyebar informasi! 📢

Pernahkah kamu melihat seseorang berteriak menggunakan pengeras suara (megaphone)? Suaranya bisa didengar oleh banyak orang tanpa harus mendatangi satu per satu. Di React, kita juga punya alat seperti pengeras suara untuk berbagi data ke banyak komponen tanpa harus mengirim props secara manual melalui setiap tingkatan. Alat itu bernama useContext!

💡 Analogi: Bayangkan di sekolah, kepala sekolah ingin mengumumkan libur. Jika dia harus memberi tahu setiap kelas satu per satu (seperti mengirim props), itu akan melelahkan. Tapi jika dia menggunakan pengeras suara (context), semua kelas bisa mendengar langsung. Komponen-komponen di React bisa "mendengarkan" context yang sama.

🧐 Masalah: Prop Drilling

Sebelum useContext, jika kita ingin mengirim data dari komponen paling atas ke komponen yang sangat dalam, kita harus mengirim props melalui komponen perantara yang mungkin tidak membutuhkan data tersebut. Ini disebut prop drilling. Ibaratnya, kamu harus menitipkan pesan melalui banyak teman, padahal teman-teman itu tidak perlu tahu isi pesannya.

Contoh: Komponen App punya data user, dan komponen Profil di dalam Sidebar di dalam Dashboard membutuhkan data itu. Maka App kirim ke Dashboard, Dashboard kirim ke Sidebar, Sidebar kirim ke Profil. Ribet!

📢 Solusi: useContext

Context memungkinkan kita membuat "pengeras suara" global untuk data tertentu. Data bisa diakses oleh komponen mana pun yang "mendengarkan" context itu, tanpa perlu props. Ada 3 langkah utama:

  1. Membuat Context dengan createContext().
  2. Menyediakan Context dengan Provider di komponen induk.
  3. Menggunakan Context dengan useContext() di komponen anak.

🛠️ Langkah 1: Membuat Context

Biasanya kita buat file terpisah untuk context, misal src/context/ThemeContext.js:

import { createContext } from 'react'; // Membuat context dengan nilai default (opsional) const ThemeContext = createContext('light'); // default: 'light' export default ThemeContext;

createContext() menghasilkan object yang berisi Provider dan Consumer. Kita akan pakai Provider nanti.

🔊 Langkah 2: Menyediakan Context (Provider)

Di komponen induk (misal App.js), kita bungkus komponen anak dengan Provider dan beri nilai (value). Nilai ini bisa berupa apa saja: string, number, object, bahkan state.

import { useState } from 'react'; import ThemeContext from './context/ThemeContext'; import Toolbar from './components/Toolbar'; function App() { const [theme, setTheme] = useState('light'); const toggleTheme = () => { setTheme(prev => prev === 'light' ? 'dark' : 'light'); }; return ( <ThemeContext.Provider value={{ theme, toggleTheme }}> <div> <h1>Aplikasi dengan Tema</h1> <Toolbar /> </div> </ThemeContext.Provider> ); }

Semua komponen di dalam Provider bisa mengakses nilai { theme, toggleTheme }.

📣 Langkah 3: Menggunakan Context (useContext)

Di komponen anak mana pun (sedalam apa pun), kita bisa gunakan useContext untuk mendapatkan nilai dari context terdekat.

Buat komponen Toolbar.js:

import { useContext } from 'react'; import ThemeContext from '../context/ThemeContext'; import Button from './Button'; function Toolbar() { const { theme, toggleTheme } = useContext(ThemeContext); return ( <div style={{ padding: '20px', background: theme === 'light' ? '#eee' : '#333' }}> <p>Tema saat ini: {theme}</p> <Button /> </div> ); }

Buat komponen Button.js (lebih dalam):

import { useContext } from 'react'; import ThemeContext from '../context/ThemeContext'; function Button() { const { theme, toggleTheme } = useContext(ThemeContext); return ( <button onClick={toggleTheme} style={{ background: theme === 'light' ? '#f7b731' : '#444', color: theme === 'light' ? '#000' : '#fff', padding: '10px 20px', borderRadius: '30px' }} > Ganti Tema </button> ); }

Lihat! Komponen Button bisa langsung mengakses toggleTheme dan theme tanpa props dari Toolbar.

🎨 Demo Simulasi Tema

Tema saat ini: light

Klik tombol di atas akan mengubah latar belakang (simulasi).

🧩 Contoh Lain: Data Pengguna (User Context)

Context sangat cocok untuk data yang digunakan banyak komponen, seperti data pengguna yang login. Buat UserContext.js:

import { createContext } from 'react'; const UserContext = createContext(null); export default UserContext;

Di App.js:

import { useState } from 'react'; import UserContext from './context/UserContext'; import Profile from './components/Profile'; function App() { const [user, setUser] = useState({ name: 'Budi', email: 'budi@example.com' }); return ( <UserContext.Provider value={user}> <Profile /> </UserContext.Provider> ); }

Di Profile.js (komponen dalam):

import { useContext } from 'react'; import UserContext from '../context/UserContext'; function Profile() { const user = useContext(UserContext); return ( <div> <p>Nama: {user.name}</p> <p>Email: {user.email}</p> </div> ); }

Tanpa props, komponen Profile bisa menampilkan data user.

⚠️ Hal Penting

  • Jangan gunakan context untuk semua data. Context bagus untuk data global seperti tema, user, bahasa. Untuk data lokal, tetap gunakan props atau state biasa.
  • Provider bisa bersarang. Jika ada beberapa context, kita bisa membungkus berlapis.
  • Jika nilai context sering berubah, semua komponen yang menggunakan context akan re-render. Untuk mengoptimalkan, pisahkan context yang jarang berubah dan sering berubah.

🧪 Latihan: Keranjang Belanja dengan Context

Buat aplikasi keranjang belanja sederhana menggunakan context. Fitur:

  1. Context CartContext menyimpan daftar item di keranjang dan fungsi untuk menambah/menghapus.
  2. Komponen ProductList menampilkan daftar produk (bisa hardcoded) dan tombol "Tambah ke Keranjang".
  3. Komponen Cart menampilkan isi keranjang dan total harga.
  4. Gunakan useContext di kedua komponen untuk mengakses state dan fungsi.

Petunjuk: Buat context dengan nilai { cart, addToCart, removeFromCart }.

💡 Tips: Untuk latihan ini, kamu bisa menyimpan cart sebagai array of objects. Fungsi addToCart bisa menambah item baru. removeFromCart bisa menyaring berdasarkan id.

🔍 Perbandingan Props vs Context

Props Context
Data dikirim manual melalui setiap tingkatan Data tersedia untuk semua komponen di dalam Provider
Cocok untuk data lokal antar komponen dekat Cocok untuk data global yang digunakan banyak komponen
Mudah dilacak alur datanya Bisa membuat alur data kurang jelas jika terlalu banyak context

🚀 Kesimpulan

  • useContext adalah solusi untuk menghindari prop drilling.
  • Buat context dengan createContext(), sediakan nilai dengan Provider, gunakan dengan useContext().
  • Context cocok untuk data global seperti tema, user, keranjang belanja.
  • Jangan berlebihan menggunakan context; pertimbangkan skala dan frekuensi perubahan data.

Di artikel selanjutnya kita akan belajar tentang useReducer, alternatif useState untuk state yang kompleks. Sampai jumpa!

Lebih baru Lebih lama

نموذج الاتصال