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 dengan createContext. 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 me-render 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 pemanggilan useContext().
  • React secara otomatis me-render ulang semua anak yang menggunakan konteks tertentu mulai dari penyedia yang menerima nilai yang berbeda. Nilai sebelumnya dan nilai berikutnya dibandingkan dengan perbandingan Object.is. Melewatkan render ulang dengan memo 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 dan SomeContext 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.

Sandungan

useContext() selalu mencari penyedia terdekat di atas komponen yang memanggilnya. Ia mencari ke atas dan tidak mempertimbangkan penyedia di dalam komponen dari yang Anda panggil useContext().

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 di-render ulang dengan nilai `‘light’ yang baru.

Examples of updating context

Contoh 1 dari 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 me-render 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 me-render 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.

Examples of overriding context

Contoh 1 dari 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 di-render 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 di-render ulang, komponen yang memanggil useContext(AuthContext) tidak perlu di-render 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:

  1. Anda me-render <SomeContext.Provider> di komponen yang sama (atau di bawahnya) dengan tempat Anda memanggil useContext(). Pindahkan <SomeContext.Provider> di atas dan di luar komponen yang memanggil useContext().
  2. 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)
  3. Anda mungkin mengalami masalah build dengan tooling Anda yang menyebabkan SomeContext yang terlihat dari komponen penyedia dan SomeContext 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 seperti window.SomeContext1 dan window.SomeContext2 dan kemudian memeriksa apakah window.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 menerimaundefined` sebagai nilai konteks.