Terakhir diperbarui: 2024-03-26
Penulis: Tim PBF 2024
Pada codelab ini Anda akan mempelajari tentang penggunaan Context di ReactJS dengan Next.js.
Sebelum memulai codelab ini, sebaiknya Anda memiliki pengetahuan dasar tentang:
Di ReactJS, context merupakan fitur yang menyediakan cara untuk mengirim data melalui pohon komponen tanpa harus melalui props secara manual pada setiap level atau tingkatan.
Biasanya aplikasi React mengirim data dengan formasi top-down (parent ke child) melalui props
, tetapi penggunaannya dapat menjadi rumit untuk beberapa jenis props (seperti pengaturan bahasa, tema UI) yang melibatkan banyak komponen dalam sebuah aplikasi. Context
menyediakan cara untuk berbagi value antar komponen tanpa melalui props pada setiap level dari komponen.
Mengoper props bisa menjadi bertele-tele dan merepotkan jika Anda harus mengopernya melalui banyak komponen di tengah-tengah, atau jika banyak komponen di aplikasi Anda membutuhkan informasi yang sama. Context
memungkinkan komponen induk untuk membuat beberapa informasi tersedia di komponen lain dalam sebuah pohon (tree) di bawahnya—tidak peduli seberapa dalam—tanpa mengopernya secara eksplisit melalui props
.
Context dirancang untuk berbagi data secara "global" ke berbagai komponen React, seperti data autentikasi pengguna yang sedang aktif, tema, atau pengaturan bahasa.
Context terutama digunakan ketika beberapa data dibutuhkan untuk diakses oleh banyak komponen pada setiap tingkatan (nesting levels). Gunakanlah dengan bijak karena itu akan mempersulit penggunaan kembali (reuse) komponen yang ada.
Mengoper props adalah cara yang bagus untuk menyalurkan data secara eksplisit melalui pohon (tree) UI Anda ke komponen yang menggunakanya.
Tapi mengoper props bisa menjadi bertele-tele dan tidak nyaman ketika Anda perlu mengoper beberapa prop secara mendalam melalui pohon (tree), atau jika banyak komponen membutuhkan prop yang sama. Bisa jadi jauh dari komponen yang membutuhkan data, dan memindahkan state ke atas dapat menyebabkan yang disebut "prop drilling".
Bukankah lebih bagus jika ada cara untuk "memindahkan" data ke komponen di dalam pohon (tree) yang membutuhkannya tanpa harus mengoper props? Dengan fitur context
React, ternyata ada!
Pada praktikum ini, Anda akan mempelajari cara menggunakan context
dengan diakses oleh komponen child didalamnya. Context
memungkinkan sebuah komponen induk menyediakan data untuk seluruh pohon (tree) di bawahnya. Ada banyak kegunaan dari context
. Berikut ini salah satu contohnya. Silakan lakukan langkah-langkah praktikum berikut ini.
Silakan buat project baru seperti berikut dan repo baru dengan nama #07-belajar-context-nextjs
Buatlah folder baru di src/components
seperti berikut ini
Buat file baru di src/components/atoms/heading.tsx
berisi kode sebagai berikut.
export default function Heading({ level, children }: { level: number; children: any }) {
switch (level) {
case 1:
return <h1>{children}</h1>;
case 2:
return <h2>{children}</h2>;
case 3:
return <h3>{children}</h3>;
case 4:
return <h4>{children}</h4>;
case 5:
return <h5>{children}</h5>;
case 6:
return <h6>{children}</h6>;
default:
throw Error('Unknown level: ' + level);
}
}
Kemudian buat file baru di src\components\atoms\section.tsx
berisi kode berikut.
export default function Section({ children }: { children: any }) {
return (
<section className="section">
{children}
</section>
);
}
Lalu bagian MainPage
buat file baru di src\components\templates\main_page.tsx
berisi kode sebagai berikut.
import Heading from "../atoms/heading";
import Section from "../atoms/section";
export default function MainPage() {
return (
<Section>
<Heading level={1}>Title</Heading>
<Section>
<Heading level={2}>Heading</Heading>
<Heading level={2}>Heading</Heading>
<Heading level={2}>Heading</Heading>
<Section>
<Heading level={3}>Sub-heading</Heading>
<Heading level={3}>Sub-heading</Heading>
<Heading level={3}>Sub-heading</Heading>
<Section>
<Heading level={4}>Sub-sub-heading</Heading>
<Heading level={4}>Sub-sub-heading</Heading>
<Heading level={4}>Sub-sub-heading</Heading>
</Section>
</Section>
</Section>
</Section>
);
}
Perhatikan komponen Heading
tersebut yang menerima level
untuk ukurannya.
Ubahlah kode di src\app\page.tsx
seperti berikut. Lalu run dan lihat hasilnya di browser Anda.
Katakanlah Anda ingin beberapa judul dalam Section
yang sama selalu memiliki ukuran yang sama.
Saat ini, Anda mengoper level
props ke tiap < Heading >
secara terpisah:
Akan lebih baik jika Anda dapat mengoper prop level ke komponen < Section >
dan menghapusnya dari komponen < Heading >
Dengan cara ini Anda dapat menerapkan bahwa semua judul di bagian yang sama memiliki ukuran yang sama:
Tapi bagaimana komponen < Heading >
dapat mengetahui level < Section >
yang terdekat? Hal ini akan membutuhkan suatu cara untuk "meminta" data dari suatu tempat di atas pohon (tree).
Anda tidak bisa melakukannya dengan props sendirian. Di sinilah context
berperan penting. Anda akan melakukannya dalam tiga langkah:
LevelContext
, karena ini untuk level judul.)Heading
akan menggunakan LevelContext
.)Section
akan menyediakan LevelContext
.)Context memungkinkan sebuah induk—bahkan yang jauh sekalipun!—menyediakan beberapa data kepada seluruh komponen pohon (tree) di dalamnya.
Pertama, Anda perlu membuat context
. Anda harus mengekspornya dari sebuah file sehingga komponen Anda dapat menggunakannya. Buatlah file baru di src\utilities\context\mycontext.tsx
yang berisi kode sebagai berikut:
Satu-satunya argumen untuk createContext
adalah nilai default. Disini, 1
merujuk pada level heading terbesar, tapi Anda dapat mengoper nilai apa pun (bahkan sebuah objek). Anda akan melihat pentingnya nilai default di langkah selanjutnya.
Ubahlah isi kode komponen Heading
dengan Impor useContext
Hook dari React dan context Anda:
Saat ini, komponen Heading
membaca level
dari props. Sebagai gantinya, hapus prop level
dan baca nilai dari context yang baru saja Anda impor, LevelContext
:
useContext
adalah sebuah Hook. Sama seperti useState
dan useReducer
, Anda hanya dapat memanggil sebuah Hook secara langsung di dalam komponen React (bukan di dalam pengulangan atau pengkondisian). useContext
memberitahu React bahwa komponen Heading
mau membaca LevelContext
.
Sekarang komponen Heading
tidak membutuhkan sebuah prop level
, Anda tidak perlu mengoper level prop ke Heading
di JSX Anda. Sebagai gantinya Perbarui JSX sehingga Section
yang dapat menerimanya:
Perhatikan contoh ini masih belum berfungsi dengan baik! Semua judul memiliki ukuran yang sama karena meskipun Anda menggunakan context, Anda belum menyediakannya. React tidak tahu darimana untuk mendapatkannya!
Jika Anda tidak menyediakan context, React akan menggunakan nilai default yang sudah Anda tentukan di langkah sebelumnya. Di contoh ini, Anda menentukan 1
sebagai argumen createContext
, jadi useContext(LevelContext)
mengembalikan 1
, mengatur semua headings ke < h1 >
. Ayo kita perbaiki masalah ini dengan membuat setiap Section
menyediakan context-nya sendiri.
Komponen Section saat ini merenders anaknya, bungkus mereka semua dengan sebuah context provider untuk menyediakan LevelContext kepada mereka seperti kode berikut:
Ini memberitahu React: "jika ada komponen di dalam < Section >
ini yang meminta LevelContext
, berikan level ini." Komponen akan menggunakan nilai dari < LevelContext.Provider >
terdekat di pohon UI (tree) di atasnya.
Hasilnya sama dengan kode aslinya, tapi Anda tidak perlu mengoper prop level
ke setiap komponen Heading
! Sebagai gantinya, ia "mencari tahu" level heading-nya dengan meminta Section
terdekat di atasnya:
level
ke < Section >
.Section
membungkus anaknya dengan < LevelContext.Provider value={level} >
.Heading
meminta nilai terdekat dari LevelContext
di atasnya dengan useContext(LevelContext)
.Saat ini, Anda masih harus menentukan setiap level section
secara manual, karena context memungkinan Anda membaca informasi dari komponen di atasnya, setiap Section
dapat membaca level
dari Section
di atasnya, dan mengoper level + 1
ke bawah secara otomatis. Berikut adalah bagaimana Anda dapat melakukannya dengan mengubah sedikit kode pada komponen Section
:
Dengan perubahan ini, Anda tidak perlu mengoper prop level baik ke < Section >
atau ke < Heading >
:
Sekarang keduanya Heading
dan Section
membaca LevelContext
untuk mencari tahu seberapa "dalam" mereka. Dan Section
membungkus anaknya ke dalam LevelContext
untuk menentukan bahwa apa pun yang ada di dalamnya berada pada level yang "lebih dalam".
Anda dapat menyisipkan sebanyak mungkin komponen di antara komponen yang menyediakan context dan komponen yang menggunakannya. Ini termasuk komponen bawaan seperti < div >
dan komponen yang mungkin Anda buat sendiri.
Di praktikum berikut, komponen Post
yang sama (dengan batas putus-putus) diberikan pada dua tingkat sarang yang berbeda. Perhatikan bahwa < Heading >
di dalamnya mendapatkan level-nya secara otomatis dari < Section >
terdekat.
Anda tidak perlu melakukan sesuatu yang khusus untuk praktikum ini. Section
menentukan context
untuk pohon (tree) di dalamnya, jadi Anda dapat menyisipkan < Heading >
di mana saja, dan akan memiliki ukuran yang benar.
Buatlah file baru di src\components\atoms\section2.tsx
berisi kode sebagai berikut.
Lalu buatlah file baru di src\components\atoms\post.tsx
dengan kode berikut.
Selanjutnya kita buat molecules di src\components\molecules\recentpost.tsx
dengan kode berikut.
Kemudian buat organisms di src\components\organisms\allpost.tsx
dengan kode berikut.
Terakhir kita buat templates di src\components\templates\profile_page.tsx
dengan kode berikut.
ProfilePage
ke page.tsx
lalu runTambahkan komponen ProfilePage
seperti kode berikut.
Hapus bagian theme
pada file tailwind.config.ts
seperti kode berikut.
Hapus semua style CSS di file src\app\globals.css
lalu ganti dengan kode berikut.
Ketika Anda run dengan npm run dev
maka di browser akan tampil seperti berikut.
Pada praktikum kali ini melanjutkan project dari praktikum sebelumnya, Anda akan membuat tema web yang bisa diubah menjadi mode light atau dark. Tampilan aplikasi web seperti berikut ini (Anda dapat berkreasi dengan konten dan style yang lain sesuai selera Anda).
Buatlah file dan folder baru di src\utilities\themes\mythemes.tsx
yang berisi kode berikut.
Kemudian buatlah contextnya di file src\utilities\contexts\mycontext.tsx
Buatlah file baru di src\components\atoms\navbar.tsx
Buatlah provider di src\components\atoms\myapp.tsx
Pindahkan komponen ProfilePage ke file src\components\templates\profile_page.tsx
Sehingga struktur folder di templates
menjadi seperti berikut. Anda dapat berkreasi dengan konten pada About
dan Contacts
.
Buatlah folder dan file baru di dalam app
agar routing page masing-masing dapat diakses seperti berikut.
Gantilah isi kode pada src\app\page.tsx
menjadi seperti berikut.
Termasuk di masing-masing page src\app\profile\page.tsx
, untuk page About dan Contacs silakan Anda sesuaikan.
Context memungkinkan Anda untuk menulis komponen yang "beradaptasi dengan sekitar mereka" dan menampilkan diri mereka secara berbeda tergantung di mana (atau, dalam kata lain, dalam context apa) mereka akan diberikan.
Cara kerja context mungkin mengingatkan Anda pada pewarisan properti CSS. Pada CSS, Anda dapat menentukan color: blue
untuk < div >
, dan simpul DOM apa pun di dalamnya, tidak peduli seberapa dalam, akan mewarisi warna tersebut kecuali ada simpul DOM lain di tengahnya yang menimpanya dengan color: green
. Demikian pula, dalam React, satu-satunya cara untuk menimpa beberapa context yang berasal dari atas adalah dengan membungkus anaknya ke dalam penyedia context dengan nilai yang berbeda.
Pada CSS, properti berbeda seperti color
dan background-color
tidak akan menimpa satu sama lain. Anda dapat mengatur semua color < div >
ke merah tanpa berdampak pada background-color
. Demikian pula, React contexts yang berbeda tidak akan menimpa satu sama lain. Tiap context yang Anda buat dengan createContext()
benar-benar terpisah dari yang lain, dan menyatukan komponen-komponen yang menggunakan dan menyediakan context tertentu. Satu komponen dapat menggunakan atau menyediakan banyak context yang berbeda tanpa masalah.
Context sangat menggoda untuk digunakan. Namun, ini juga terlalu mudah untuk menggunakannya secara berlebihan. Hanya karena Anda membutuhkan untuk mengoper beberapa props beberapa tingkat lebih dalam bukan berarti Anda memasukkan informasi tersebut ke dalam context.
Ini adalah beberapa alternatif yang harus Anda pertimbangkan sebelum menggunakan context:
posts
ke komponen visual yang tidak menggunakannya secara langsung, seperti < Layout posts={posts} / >
. Sebagai gantinya, buat Layout
mengambil children
sebagai prop, dan berikan < Layout > < Posts posts={posts} / >< / Layout >
. Hal ini mengurangi jumlah lapisan antara komponen yang menentukan data dan komponen yang membutuhkannya.Jika tidak satu pun dari pendekatan ini yang cocok untuk Anda, pertimbangkan dalam menggunakan context
.
Context tidak terbatas pada nilai statis. Jika anda memberikan nilai yang berbeda pada render berikutnya, React akan memperbarui semua komponen yang membacanya di bawahnya! Inilah sebabnya mengapa context sering digunakan bersama degan state.
Pada umumnya, jika beberapa informasi dibutuhkan oleh komponen yang jauh di beberapa bagian pohon (tree), ini adalah indikasi yang bagus bahwa context akan membantu Anda.
export const MyContext = createContext(defaultValue)
.useContext(MyContext)
Hook untuk membacanya di komponen anak manapun, tidak peduli seberapa dalam.< MyContext.Provider value={...} >
untuk menyediakannya dari induk.children
.Selamat, Anda telah berhasil menyelesaikan codelab ini. Semoga mendapatkan ilmu yang bermanfaat.
Silakan cek beberapa sumber belajar lainnya...