useContext
useContext
adalah sebuah React Hook yang memungkinkan Anda membaca dan berlangganan dengan context dari komponen Anda.
const value = useContext(SomeContext)
Referensi
useContext(SomeContext)
Panggil fungsi useContext
di tingkat atas komponen Anda untuk membaca dan berlangganan dengan context.
import { useContext } from 'react';
function MyComponent() {
const theme = useContext(ThemeContext);
// ...
Lihat contoh lainnya di bawah ini.
Parameters
SomeContext
: Konteks yang sebelumnya telah Anda buat dengancreateContext
. Konteks itu sendiri tidak menyimpan informasi, konteks hanya merepresentasikan jenis informasi yang dapat Anda berikan atau baca dari komponen.
Returns
useContext
mengembalikan nilai konteks untuk komponen yang dipanggil. Nilai ini ditentukan sebagai value
yang dioper ke SomeContext.Provider
terdekat di atas komponen pemanggil dalam pohon. Jika tidak ada penyedia tersebut, maka nilai yang dikembalikan adalah defaultValue
yang telah Anda berikan ke createContext
untuk konteks tersebut. Nilai yang dikembalikan selalu mutakhir. React secara otomatis merender ulang komponen yang membaca suatu konteks jika konteks tersebut berubah.
Caveats
- Pemanggilan
useContext()
dalam sebuah komponen tidak terpengaruh oleh provider yang dikembalikan dari komponen yang sama.<Context.Provider>
yang sesuai harus berada di atas komponen yang melakukan pemanggilanuseContext()
. - React secara otomatis merender ulang semua anak yang menggunakan konteks tertentu mulai dari penyedia yang menerima
nilai
yang berbeda. Nilai sebelumnya dan nilai berikutnya dibandingkan dengan perbandinganObject.is
. Melewatkan render ulang denganmemo
tidak mencegah anak-anak menerima nilai konteks yang baru. - Jika sistem build Anda menghasilkan modul duplikat pada keluaran (yang dapat terjadi pada symlink), ini dapat merusak konteks. Mengoper sesuatu melalui konteks hanya berfungsi jika
SomeContext
yang Anda gunakan untuk memberikan konteks danSomeContext
yang Anda gunakan untuk membacanya adalah objek yang sama persis, seperti yang ditentukan oleh perbandingan===
.
Penggunaan
Mengoper data secara mendalam ke dalam pohon
Panggil useContext
di tingkat atas komponen Anda untuk membaca dan berlangganan ke context.
import { useContext } from 'react';
function Button() {
const theme = useContext(ThemeContext);
// ...
useContext
mengembalikan nilai konteks untuk konteks yang telah Anda oper. Untuk menentukan nilai konteks, React mencari di pohon komponen dan menemukan penyedia konteks terdekat di atas untuk konteks tertentu.
Untuk mengoper konteks ke sebuah Button
, bungkus komponen tersebut atau salah satu komponen induknya ke dalam penyedia konteks yang sesuai:
function MyPage() {
return (
<ThemeContext.Provider value="dark">
<Form />
</ThemeContext.Provider>
);
}
function Form() {
// ... renders buttons inside ...
}
Tidak masalah berapa banyak lapisan komponen yang ada di antara penyedia dan Button
. Ketika sebuah Button
di mana saja di dalam Form
memanggil useContext(ThemeContext)
, maka akan menerima "dark"
sebagai nilai.
import { createContext, useContext } from 'react'; const ThemeContext = createContext(null); export default function MyApp() { return ( <ThemeContext.Provider value="dark"> <Form /> </ThemeContext.Provider> ) } function Form() { return ( <Panel title="Welcome"> <Button>Sign up</Button> <Button>Log in</Button> </Panel> ); } function Panel({ title, children }) { const theme = useContext(ThemeContext); const className = 'panel-' + theme; return ( <section className={className}> <h1>{title}</h1> {children} </section> ) } function Button({ children }) { const theme = useContext(ThemeContext); const className = 'button-' + theme; return ( <button className={className}> {children} </button> ); }
Memperbarui data yang dioper melalui konteks
Sering kali, Anda ingin konteks berubah seiring berjalannya waktu. Untuk memperbarui konteks, kombinasikan dengan state. Deklarasikan variabel state dalam komponen induk, dan berikan state saat ini sebagai context value ke penyedia.
function MyPage() {
const [theme, setTheme] = useState('dark');
return (
<ThemeContext.Provider value={theme}>
<Form />
<Button onClick={() => {
setTheme('light');
}}>
Switch to light theme
</Button>
</ThemeContext.Provider>
);
}
Sekarang setiap Button
di dalam penyedia akan menerima nilai theme
saat ini. Jika Anda memanggil setTheme
untuk memperbarui nilai theme
yang Anda berikan ke penyedia, semua komponen Button
akan dirender ulang dengan nilai `‘light’ yang baru.
Example 1 of 5: Memperbarui nilai melalui konteks
Dalam contoh ini, komponen MyApp
menyimpan variabel status yang kemudian diteruskan ke penyedia ThemeContext
. Mencentang kotak centang “Dark mode” akan memperbarui state. Mengubah nilai yang disediakan akan merender ulang semua komponen yang menggunakan konteks tersebut.
import { createContext, useContext, useState } from 'react'; const ThemeContext = createContext(null); export default function MyApp() { const [theme, setTheme] = useState('light'); return ( <ThemeContext.Provider value={theme}> <Form /> <label> <input type="checkbox" checked={theme === 'dark'} onChange={(e) => { setTheme(e.target.checked ? 'dark' : 'light') }} /> Use dark mode </label> </ThemeContext.Provider> ) } function Form({ children }) { return ( <Panel title="Welcome"> <Button>Sign up</Button> <Button>Log in</Button> </Panel> ); } function Panel({ title, children }) { const theme = useContext(ThemeContext); const className = 'panel-' + theme; return ( <section className={className}> <h1>{title}</h1> {children} </section> ) } function Button({ children }) { const theme = useContext(ThemeContext); const className = 'button-' + theme; return ( <button className={className}> {children} </button> ); }
Perhatikan bahwa value="dark"
meneruskan string "dark"
, tetapi value={theme}
meneruskan nilai variabel theme
JavaScript dengan kurung kurawal JSX. Kurung kurawal juga memungkinkan Anda mengoper nilai konteks yang bukan string.
Menentukan nilai default fallback
Jika React tidak dapat menemukan penyedia context tertentu di pohon induk, nilai konteks yang dikembalikan oleh useContext()
akan sama dengan default value yang Anda tentukan ketika Anda membuat konteks tersebut:
const ThemeContext = createContext(null);
Nilai default tidak pernah berubah. Jika Anda ingin memperbarui konteks, gunakan dengan status seperti yang dijelaskan di atas.
Sering kali, alih-alih null
, ada beberapa nilai yang lebih berarti yang dapat Anda gunakan sebagai default, misalnya:
const ThemeContext = createContext('light');
Dengan cara ini, jika Anda secara tidak sengaja merender beberapa komponen tanpa penyedia yang sesuai, komponen tersebut tidak akan rusak. Hal ini juga membantu komponen Anda bekerja dengan baik di lingkungan pengujian tanpa menyiapkan banyak provider dalam pengujian.
Pada contoh di bawah ini, tombol “Toggle theme” selalu berwarna terang karena tombol tersebut berada di luar penyedia konteks tema apa pun dan nilai tema konteks default adalah `‘light’. Cobalah mengedit tema default menjadi ‘dark’.
import { createContext, useContext, useState } from 'react'; const ThemeContext = createContext('light'); export default function MyApp() { const [theme, setTheme] = useState('light'); return ( <> <ThemeContext.Provider value={theme}> <Form /> </ThemeContext.Provider> <Button onClick={() => { setTheme(theme === 'dark' ? 'light' : 'dark'); }}> Toggle theme </Button> </> ) } function Form({ children }) { return ( <Panel title="Welcome"> <Button>Sign up</Button> <Button>Log in</Button> </Panel> ); } function Panel({ title, children }) { const theme = useContext(ThemeContext); const className = 'panel-' + theme; return ( <section className={className}> <h1>{title}</h1> {children} </section> ) } function Button({ children, onClick }) { const theme = useContext(ThemeContext); const className = 'button-' + theme; return ( <button className={className} onClick={onClick}> {children} </button> ); }
Menggantikan konteks untuk bagian dari pohon
Anda dapat mengganti konteks untuk suatu bagian pohon dengan membungkus bagian tersebut dengan penyedia bersama nilai yang berbeda.
<ThemeContext.Provider value="dark">
...
<ThemeContext.Provider value="light">
<Footer />
</ThemeContext.Provider>
...
</ThemeContext.Provider>
Anda bisa membuat sarang dan menimpa penyedia sebanyak yang Anda butuhkan.
Example 1 of 2: Menggantikan sebuah tema
Di sini, tombol di dalam Footer
menerima nilai konteks yang berbeda ("light"
) daripada tombol di luar ("dark"
).
import { createContext, useContext } from 'react'; const ThemeContext = createContext(null); export default function MyApp() { return ( <ThemeContext.Provider value="dark"> <Form /> </ThemeContext.Provider> ) } function Form() { return ( <Panel title="Welcome"> <Button>Sign up</Button> <Button>Log in</Button> <ThemeContext.Provider value="light"> <Footer /> </ThemeContext.Provider> </Panel> ); } function Footer() { return ( <footer> <Button>Settings</Button> </footer> ); } function Panel({ title, children }) { const theme = useContext(ThemeContext); const className = 'panel-' + theme; return ( <section className={className}> {title && <h1>{title}</h1>} {children} </section> ) } function Button({ children }) { const theme = useContext(ThemeContext); const className = 'button-' + theme; return ( <button className={className}> {children} </button> ); }
Mengoptimalkan render ulang saat mengoper objek dan fungsi
Anda dapat mengoper nilai apa pun melalui konteks, termasuk objek dan fungsi.
function MyApp() {
const [currentUser, setCurrentUser] = useState(null);
function login(response) {
storeCredentials(response.credentials);
setCurrentUser(response.user);
}
return (
<AuthContext.Provider value={{ currentUser, login }}>
<Page />
</AuthContext.Provider>
);
}
Di sini, context value adalah sebuah objek JavaScript dengan dua properti, salah satunya adalah sebuah fungsi. Setiap kali MyApp
dirender ulang (misalnya, pada pembaruan rute), ini akan menjadi objek berbeda yang menunjuk ke fungsi berbeda, sehingga React juga harus me-render ulang semua komponen di dalam pohon yang memanggil useContext(AuthContext)
.
Pada aplikasi yang lebih kecil, hal ini tidak menjadi masalah. Namun, tidak perlu me-render ulang jika data yang mendasarinya, seperti currentUser
, tidak berubah. Untuk membantu React memanfaatkan fakta tersebut, Anda dapat membungkus fungsi login
dengan useCallback
dan membungkus pembuatan objek ke dalam useMemo
. Hal ini merupakan pengoptimalan kinerja:
import { useCallback, useMemo } from 'react';
function MyApp() {
const [currentUser, setCurrentUser] = useState(null);
const login = useCallback((response) => {
storeCredentials(response.credentials);
setCurrentUser(response.user);
}, []);
const contextValue = useMemo(() => ({
currentUser,
login
}), [currentUser, login]);
return (
<AuthContext.Provider value={contextValue}>
<Page />
</AuthContext.Provider>
);
}
Sebagai hasil dari perubahan ini, meskipun MyApp
perlu dirender ulang, komponen yang memanggil useContext(AuthContext)
tidak perlu dirender ulang kecuali jika currentUser
telah berubah.
Baca lebih lanjut tentang [useMemo
]((/reference/react/useMemo#skipping-re-rendering-of-components) dan useCallback
.
Pemecahan Masalah
Komponen saya tidak melihat nilai dari penyedia saya
Ada beberapa cara umum yang dapat menyebabkan hal ini terjadi:
- Anda merender
<SomeContext.Provider>
di komponen yang sama (atau di bawahnya) dengan tempat Anda memanggiluseContext()
. Pindahkan<SomeContext.Provider>
di atas dan di luar komponen yang memanggiluseContext()
. - Anda mungkin lupa membungkus komponen Anda dengan
<SomeContext.Provider>
, atau Anda mungkin meletakkannya di bagian pohon yang berbeda dari yang Anda kira. Periksa apakah hirarki sudah benar dengan menggunakan [React DevTools.] (/learn/react-developer-tools) - Anda mungkin mengalami masalah build dengan tooling Anda yang menyebabkan
SomeContext
yang terlihat dari komponen penyedia danSomeContext
yang terlihat oleh komponen pembacaan menjadi dua objek yang berbeda. Hal ini dapat terjadi jika Anda menggunakan symlink, misalnya. Anda dapat memverifikasi hal ini dengan menugaskan mereka ke global sepertiwindow.SomeContext1
danwindow.SomeContext2
dan kemudian memeriksa apakahwindow.SomeContext1 === window.SomeContext2
di konsol. Jika tidak sama, perbaiki masalah tersebut di tingkat build tool.
Saya selalu mendapatkan undefined
dari konteks saya meskipun nilai defaultnya berbeda
Anda mungkin memiliki penyedia tanpa value
di dalam pohon:
// 🚩 Doesn't work: no value prop
<ThemeContext.Provider>
<Button />
</ThemeContext.Provider>
Jika Anda lupa menentukan value
, ini sama saja dengan mengoper value={undefined}
.
Anda mungkin juga tidak sengaja menggunakan nama prop yang berbeda:
// 🚩 Doesn't work: prop should be called "value"
<ThemeContext.Provider theme={theme}>
<Button />
</ThemeContext.Provider>
Pada kedua kasus ini, Anda akan melihat peringatan dari React di konsol. Untuk memperbaikinya, panggil prop value
:
// ✅ Passing the value prop
<ThemeContext.Provider value={theme}>
<Button />
</ThemeContext.Provider>
Perhatikan bahwa [nilai default dari panggilan createContext(defaultValue)
Anda] (#specifying-a-fallback-default-value) hanya digunakan **jika tidak ada penyedia yang cocok di atas sama sekali **Jika ada komponen <SomeContext.Provider value = {undefined}>
di suatu tempat di dalam pohon induk, komponen yang memanggil useContext(SomeContext)
akan menerima
undefined` sebagai nilai konteks.