useContext γ―γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ§γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆ (Context) οΏ½?θͺ­γΏε–γ‚Šγ¨γ‚΅γƒ–γ‚Ήγ‚―γƒ©γ‚€γƒ–οΌˆsubscribe, 倉更�?ε—γ‘ε–γ‚ŠοΌ‰γ‚’θ‘Œγ†γŸγ‚οΏ½? React フックです。

const value = useContext(SomeContext)

γƒͺフゑレンス

useContext(SomeContext)

γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆοΏ½?γƒˆγƒƒγƒ—γƒ¬γƒ™γƒ«γ§ useContext γ‚’ε‘Όγ³ε‡Ίγ—γ¦γ€γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγ‚’θͺ­γΏε–γ‚Šγ€γ‚΅γƒ–γ‚Ήγ‚―ラむブします。

import { useContext } from 'react';

function MyComponent() {
const theme = useContext(ThemeContext);
// ...

さらに例を見る

εΌ•ζ•°

  • SomeContext: 事前に createContext γ§δ½œζˆγ—γŸγ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγ§γ™γ€‚γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγ¨γ―γγ‚Œθ‡ͺδ½“γŒζƒ…ε ±γ‚’δΏζŒγ—γ¦γ„γ‚‹γ‚γ‘γ§γ―γͺγγ€γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ§ζδΎ› (provide) γ—γŸγ‚Šθͺ­γΏε–γ£γŸγ‚Šγ§γγ‚‹γ€Œζƒ…ε ±οΏ½?οΏ½?εˆ₯」を葨すも�?です。

θΏ”γ‚Šε€€

useContext γ―γ€ε‘Όγ³ε‡Ίγ—γŸγ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ«ε―ΎεΏœγ™γ‚‹γ‚³γƒ³γƒ†γ‚―γ‚ΉγƒˆοΏ½?倀を返します。倀は、ツγƒͺー内で useContext γ‚’ε‘Όγ³ε‡Ίγ—γŸγ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆοΏ½?δΈŠδ½γ‹γ€ζœ€γ‚‚θΏ‘γ„ SomeContext.Provider γ«ζΈ‘γ•γ‚ŒγŸ value として決�?οΏ½γ•γ‚ŒγΎγ™γ€‚γοΏ½?γ‚ˆγ†γͺγƒ—γƒ­γƒγ‚€γƒ€γŒε­˜εœ¨γ—γͺγ„ε ΄εˆγ―γ€θΏ”γ‚Šε€€γ―γοΏ½?γ‚³γƒ³γƒ†γ‚―γ‚ΉγƒˆοΏ½? createContext γ«ζΈ‘γ—γŸ defaultValue にγͺγ‚ŠγΎγ™γ€‚θΏ”γ‚Šε€€γ―εΈΈγ«γ‚³γƒ³γƒ†γ‚―γ‚ΉγƒˆοΏ½?ζœ€ζ–°οΏ½?倀です。React γ―γ€γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγ«ε€‰ζ›΄γŒγ‚γ‚‹γ¨γ€γγ‚Œγ‚’θͺ­γΏε–γ£γ¦γ„γ‚‹γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ‚’θ‡ͺε‹•ηš„γ«ε†γƒ¬γƒ³γƒ€γƒΌγ—γΎγ™γ€‚

注意点

  • γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆοΏ½? useContext() ε‘Όγ³ε‡Ίγ—γ―γ€εŒγ˜γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ‹γ‚‰θΏ”γ•γ‚Œγ‚‹γƒ—γƒ­γƒγ‚€γƒ€οΏ½?ε½±ιŸΏγ‚’ε—γ‘γΎγ›γ‚“γ€‚ε―ΎεΏœγ™γ‚‹ <Context.Provider> は、useContext() γ‚’ε‘Όγ³ε‡Ίγ™γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆοΏ½?δΈŠγ«γ‚γ‚‹εΏ…θ¦γŒγ‚γ‚ŠγΎγ™γ€‚
  • γ‚γ‚‹γ‚³γƒ³γƒ†γ‚―γ‚ΉγƒˆοΏ½?γƒ—γƒ­γƒγ‚€γƒ€γŒη•°γͺγ‚‹ value γ‚’ε—γ‘ε–γ‚‹γ¨γ€ε½“θ©²γƒ—γƒ­γƒγ‚€γƒ€γ‚ˆγ‚ŠδΈ‹γ«γ‚γ‚ŠγοΏ½?γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγ‚’δ½Ώη”¨γ—γ¦γ„γ‚‹γ™γΉγ¦οΏ½?ε­γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ―γ€React γ«γ‚ˆγ£γ¦θ‡ͺε‹•ηš„γ«ε†γƒ¬γƒ³γƒ€γƒΌγ•γ‚ŒγΎγ™γ€‚ε‰οΏ½?倀と欑�?倀は、Object.is γ§ζ―”θΌƒγ•γ‚ŒγΎγ™γ€‚memo γ‚’δ½Ώγ£γ¦ε†γƒ¬γƒ³γƒ€γƒΌγ‚’γ‚Ήγ‚­γƒƒγƒ—γ™γ‚‹ε ΄εˆγ§γ‚‚γ€ε­γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγŒγ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγ‹γ‚‰ζ–°γ—γ„ε€€γ‚’ε—γ‘ε–γ‚‹γ“γ¨γ«γ‚ˆγ‚‹ε†γƒ¬γƒ³γƒ€γƒΌγ―ε¦¨γ’γ‚‰γ‚ŒγΎγ›γ‚“γ€‚
  • γƒ“γƒ«γƒ‰γ‚·γ‚Ήγƒ†γƒ γŒη”Ÿζˆγ™γ‚‹ε‡ΊεŠ›οΏ½?中にヒジγƒ₯ール�?ι‡θ€‡γŒγ‚γ‚‹ε ΄εˆοΌˆγ‚·γƒ³γƒœγƒͺックγƒͺγƒ³γ‚―γ§θ΅·γ“γ‚ŠεΎ—γ‚‹ε ΄εˆγŒγ‚γ‚‹οΌ‰γ€γ‚³γƒ³γƒ†γ‚―γ‚ΉγƒˆγŒε£Šγ‚Œγ‚‹ε―θƒ½ζ€§γŒγ‚γ‚ŠγΎγ™γ€‚γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγ‚’δ»‹γ—γŸε€€οΏ½?ε—γ‘ζΈ‘γ—γŒε‹•δ½œγ™γ‚‹οΏ½?γ―γ€γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγ‚’ζδΎ›γ™γ‚‹γŸγ‚γ«δ½Ώη”¨γ™γ‚‹ SomeContext と、θͺ­γΏθΎΌγ‚€γŸγ‚γ«δ½Ώη”¨γ™γ‚‹ SomeContext γŒγ€=== γ«γ‚ˆγ‚‹ζ―”θΌƒγ§εŽ³ε―†γ«εŒγ˜γ‚ͺγƒ–γ‚Έγ‚§γ‚―γƒˆγ§γ‚γ‚‹ε ΄εˆοΏ½?みです。

使用法

ツγƒͺγƒΌοΏ½?深くにデータを渑す

γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆοΏ½?γƒˆγƒƒγƒ—γƒ¬γƒ™γƒ«γ§ useContext γ‚’ε‘Όγ³ε‡Ίγ—γ¦γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγ‚’θͺ­γΏε–γ‚Šγ€γ‚΅γƒ–γ‚Ήγ‚―ラむブします。

import { useContext } from 'react';

function Button() {
const theme = useContext(ThemeContext);
// ...

useContext γ―ζΈ‘γ—γŸγ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγ«ε―ΎεΏœγ™γ‚‹γ‚³γƒ³γƒ†γ‚―γ‚ΉγƒˆοΏ½?ε€€γ‚’θΏ”γ—γΎγ™γ€‚γ‚³γƒ³γƒ†γ‚―γ‚ΉγƒˆοΏ½?ε€€γ‚’ζ±ΊοΏ½?οΏ½γ™γ‚‹γŸγ‚γ«γ€React γ―γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγƒ„γƒͺγƒΌγ‚’ζŽ’η΄’γ—γ€γοΏ½?γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγ«ε―Ύγ—γ¦ζœ€γ‚‚θΏ‘γ„δΈŠδ½οΏ½?γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγƒ—γƒ­γƒγ‚€γƒ€γ‚’θ¦‹γ€γ‘γΎγ™γ€‚

γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγ‚’δΈŠθ¨˜οΏ½? Button に渑すには、該当�?γƒœγ‚Ώγƒ³γ‚γ‚‹γ„γ―γοΏ½?θ¦ͺγ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆοΏ½?γ„γšγ‚Œγ‹γ‚’γ€ε―ΎεΏœγ™γ‚‹γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγƒ—γƒ­γƒγ‚€γƒ€γ§γƒ©γƒƒγƒ—γ—γΎγ™γ€‚

function MyPage() {
return (
<ThemeContext.Provider value="dark">
<Form />
</ThemeContext.Provider>
);
}

function Form() {
// ... renders buttons inside ...
}

プロバむダと Button οΏ½?ι–“γ«γ©γ‚Œγ γ‘ε€šγοΏ½?γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγŒζŒŸγΎγ£γ¦γ„γ¦γ‚‚ι–’δΏ‚γ‚γ‚ŠγΎγ›γ‚“γ€‚Form οΏ½?内部�?どこかで Button が useContext(ThemeContext) を呼び出すとき、倀として "dark" γ‚’ε—γ‘ε–γ‚ŠγΎγ™γ€‚

落とし穴

useContext() γ―εΈΈγ«γ€ε‘Όγ³ε‡Ίγ™γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ‚ˆγ‚Šζœ€γ‚‚θΏ‘γ„γ€δΈŠδ½γ«γ‚γ‚‹γƒ—γƒ­γƒγ‚€γƒ€γ‚’ζŽ’γ—γΎγ™γ€‚δΈŠζ–Ήε‘γ«ζŽ’η΄’γ‚’θ‘Œγ†οΏ½?で、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>
  );
}


γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆη΅Œη”±γ§ζΈ‘γ•γ‚ŒγŸγƒ‡γƒΌγ‚ΏοΏ½?ζ›΄ζ–°

倚く�?ε ΄εˆγ€ζ™‚ι–“γ¨γ¨γ‚‚γ«γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγ‚’ε€‰εŒ–γ•γ›γŸγ„γ¨ζ€γ†γ§γ—γ‚‡γ†γ€‚γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγ‚’ζ›΄ζ–°γ™γ‚‹γ«γ―γ€γγ‚Œγ‚’ state γ¨η΅„γΏεˆγ‚γ›γΎγ™γ€‚θ¦ͺγ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ§ state 倉数を�?οΏ½θ¨€γ—γ€ηΎεœ¨οΏ½? state γ‚’γ‚³γƒ³γƒ†γ‚―γ‚ΉγƒˆοΏ½?倀としてプロバむダに渑します。

function MyPage() {
const [theme, setTheme] = useState('dark');
return (
<ThemeContext.Provider value={theme}>
<Form />
<Button onClick={() => {
setTheme('light');
}}>
Switch to light theme
</Button>
</ThemeContext.Provider>
);
}

γ“γ‚Œγ«γ‚ˆγ‚Šγ€γƒ—γƒ­γƒγ‚€γƒ€οΏ½?内部にある、ど�? Button γ‚‚ηΎεœ¨οΏ½? theme οΏ½?ε€€γ‚’ε—γ‘ε–γ‚‹γ‚ˆγ†γ«γͺγ‚ŠγΎγ™γ€‚setTheme を呼び出してプロバむダに渑す theme 倀を更新すると、すべて�? Button γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ―ζ–°γŸγͺ倀である 'light' γ‚’δ½Ώγ£γ¦ε†γƒ¬γƒ³γƒ€γƒΌγ•γ‚ŒγΎγ™γ€‚

Examples of updating context

δΎ‹ 1/5:
γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆη΅Œη”±γ§ζΈ‘γ•γ‚ŒγŸε€€οΏ½?ζ›΄ζ–°

こ�?例では、MyApp γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγŒ state ε€‰ζ•°γ‚’δΏζŒγ—γ€γγ‚ŒγŒ ThemeContext γƒ—γƒ­γƒγ‚€γƒ€γ«ζΈ‘γ•γ‚ŒγΎγ™γ€‚β€œDark mode” οΏ½?γƒγ‚§γƒƒγ‚―γƒœγƒƒγ‚―γ‚Ήγ‚’ιΈζŠžγ™γ‚‹γ¨γ€state γŒζ›΄ζ–°γ•γ‚ŒγΎγ™γ€‚γƒ—γƒ­γƒγ‚€γƒ€γ«ζΈ‘γ™ε€€γ‚’ζ›΄ζ–°γ™γ‚‹γ¨γ€γοΏ½?γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγ‚’δ½Ώη”¨γ—γ¦γ„γ‚‹γ™γΉγ¦οΏ½?γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγŒε†γƒ¬γƒ³γƒ€γƒΌγ•γ‚ŒγΎγ™γ€‚

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>
  );
}

value="dark" は "dark" γ¨γ„γ†ζ–‡ε­—εˆ—γ‚’ζΈ‘γ—γΎγ™γŒγ€value={theme} は JavaScript οΏ½? theme 倉数�?ε€€γ‚’ JSX οΏ½?ζ³’ζ‹¬εΌ§γ§ζΈ‘γ—γ¦γ„γ‚‹γ“γ¨γ«ζ³¨ζ„γ—γ¦γγ γ•γ„γ€‚ζ³’ζ‹¬εΌ§γ‚’δ½Ώγ†γ“γ¨γ§γ€ζ–‡ε­—εˆ—δ»₯ε€–οΏ½?γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆε€€γ‚‚ζΈ‘γ™γ“γ¨γŒγ§γγΎγ™γ€‚


フォールバックとγͺγ‚‹γƒ‡γƒ•γ‚©γƒ«γƒˆε€€οΏ½?ζŒ‡οΏ½?οΏ½

React γŒγ‚γ‚‹γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγ«ε―ΎεΏœγ™γ‚‹γƒ—γƒ­γƒγ‚€γƒ€γ‚’θ¦ͺツγƒͺγƒΌγ§θ¦‹γ€γ‘γ‚‰γ‚Œγͺγ„ε ΄εˆγ€useContext() γŒθΏ”γ™γ‚³γƒ³γƒ†γ‚―γ‚ΉγƒˆοΏ½?ε€€γ―γ€γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγ‚’δ½œζˆγ—γŸγ¨γγ«ζŒ‡οΏ½?οΏ½γ—γŸγƒ‡γƒ•γ‚©γƒ«γƒˆε€€γ¨η­‰γ—γγͺγ‚ŠγΎγ™οΌš

const ThemeContext = createContext(null);

γƒ‡γƒ•γ‚©γƒ«γƒˆε€€γ―η΅Άε―Ύγ«ε€‰ζ›΄γ•γ‚ŒγΎγ›γ‚“γ€‚γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγ‚’ζ›΄ζ–°γ—γŸγ„ε ΄εˆγ€δΈŠθ¨˜γ§θͺ¬ζ˜Žγ—γŸγ‚ˆγ†γ«γ€state γ¨η΅„γΏεˆγ‚γ›γ¦δ½Ώη”¨γ—γΎγ™γ€‚

倚く�?ε ΄εˆγ€null οΏ½?δ»£γ‚γ‚Šγ«γƒ‡γƒ•γ‚©γƒ«γƒˆε€€γ¨γ—γ¦δ½Ώγˆγ‚‹γ€ζ„ε‘³οΏ½?γ‚γ‚‹ε€€γŒγ‚γ‚‹γ―γšγ§γ™γ€‚δΎ‹γˆγ°οΌš

const ThemeContext = createContext('light');

γ“γ†γ™γ‚Œγ°γ€ε―ΎεΏœγ™γ‚‹γƒ—γƒ­γƒγ‚€γƒ€γͺγ—γ«γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ‚’ι–“ι•γ£γ¦γƒ¬γƒ³γƒ€γƒΌγ—γ¦γ—γΎγ£γ¦γ‚‚γ€ε£Šγ‚Œγ‚‹γ“γ¨γ―γ‚γ‚ŠγΎγ›γ‚“γ€‚γƒ†γ‚Ήγƒˆη’°ε’ƒγ§γ‚‚γ€γƒ†γ‚Ήγƒˆγ‚³γƒΌγƒ‰γ«γƒ—γƒ­γƒγ‚€γƒ€γ‚’γŸγγ•γ‚“θ¨­οΏ½?οΏ½γ›γšγ¨γ‚‚γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγŒγ†γΎγε‹•δ½œγ™γ‚‹γ‚ˆγ†γ«γͺγ‚ŠγΎγ™γ€‚

δΈ‹θ¨˜οΏ½?δΎ‹γ§γ―γ€β€œToggle theme” γƒœγ‚Ώγƒ³γ―γ‚γ‚‰γ‚†γ‚‹γƒ†γƒΌγƒžγ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγƒ—γƒ­γƒγ‚€γƒ€οΏ½?ε€–ιƒ¨γ«γ‚γ‚Šγ€γ‹γ€γƒ†γƒΌγƒžγ‚³γƒ³γƒ†γ‚―γ‚ΉγƒˆοΏ½?γƒ‡γƒ•γ‚©γƒ«γƒˆε€€γŒ 'light' γ§γ‚γ‚‹γŸγ‚γ€εΈΈγ« light οΏ½?色θͺΏγ§θ‘¨η€Ίγ•γ‚ŒγΎγ™γ€‚γƒ†γƒΌγƒžοΏ½?εˆζœŸε€€γ‚’ '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>
  );
}


ツγƒͺγƒΌοΏ½?δΈ€ιƒ¨γ§γ‚³γƒ³γƒ†γ‚―γ‚ΉγƒˆοΏ½?ε€€γ‚’δΈŠζ›Έγγ™γ‚‹

η•°γͺγ‚‹ε€€γ‚’ζŒγ€γƒ—γƒ­γƒγ‚€γƒ€γ§γƒ„γƒͺγƒΌοΏ½?δΈ€ιƒ¨γ‚’γƒ©γƒƒγƒ—γ™γ‚‹γ“γ¨γ«γ‚ˆγ‚Šγ€γοΏ½?ιƒ¨εˆ†οΏ½?γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγ‚’δΈŠζ›Έγγ§γγΎγ™γ€‚

<ThemeContext.Provider value="dark">
...
<ThemeContext.Provider value="light">
<Footer />
</ThemeContext.Provider>
...
</ThemeContext.Provider>

プロバむダ�?γƒγ‚Ήγƒˆγ¨δΈŠζ›Έγγ―εΏ…θ¦γͺγ γ‘θ‘Œγ†γ“γ¨γŒγ§γγΎγ™γ€‚

Examples of overriding context

δΎ‹ 1/2:
γƒ†γƒΌγƒžοΏ½?δΈŠζ›Έγ

こ�?例では、Footer οΏ½?ε†…ιƒ¨γ«γ‚γ‚‹γƒœγ‚Ώγƒ³γ―γ€ε€–ιƒ¨γ«γ‚γ‚‹γƒœγ‚Ώγƒ³οΌˆ"dark"οΌ‰γ¨γ―ι•γ†γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆε€€οΌˆ"light"οΌ‰γ‚’ε—γ‘ε–γ‚ŠγΎγ™γ€‚

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>
  );
}


γ‚ͺγƒ–γ‚Έγ‚§γ‚―γƒˆγ‚„ι–’ζ•°γ‚’ζΈ‘γ™γ¨γοΏ½?再レンダー�?ζœ€ι©εŒ–

γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγ‚’δ»‹γ—γ¦γ€γ‚ͺγƒ–γ‚Έγ‚§γ‚―γƒˆγ‚„ι–’ζ•°γ‚’ε«γ‚“γ γ©γ‚“γͺε€€γ‚‚ζΈ‘γ™γ“γ¨γŒγ§γγΎγ™γ€‚

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>
);
}

γ“γ“γ§γ―γ€γ‚³γƒ³γƒ†γ‚―γ‚ΉγƒˆοΏ½?倀は、2 ぀�?γƒ—γƒ­γƒ‘γƒ†γ‚£γ‚’ζŒγ€ JavaScript γ‚ͺγƒ–γ‚Έγ‚§γ‚―γƒˆγ§γ‚γ‚Šγ€γοΏ½?うけ�? 1 ぀は閒数にγͺγ‚ŠγΎγ™γ€‚MyApp γŒε†γƒ¬γƒ³γƒ€γƒΌγ•γ‚Œγ‚‹γŸγ³γ«οΌˆδΎ‹γˆγ°γ€γƒšγƒΌγ‚Έι·η§»γͺγ©οΌ‰γ€γ“γ‚Œγ―η•°γͺγ‚‹ι–’ζ•°οΏ½?ε…₯γ£γŸη•°γͺγ‚‹γ‚ͺγƒ–γ‚Έγ‚§γ‚―γƒˆγ‚’ζŒ‡γ™γŸγ‚γ€React はツγƒͺーにある useContext(AuthContext) を呼び出しているすべて�?γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ‚’ε†γƒ¬γƒ³γƒ€γƒΌγ—γͺγ‘γ‚Œγ°γͺγ‚ŠγΎγ›γ‚“γ€‚

小規樑γͺγ‚’γƒ—γƒͺγ§γ―γ€ε•ι‘Œγ«γͺγ‚ŠγΎγ›γ‚“γ€‚γ§γ™γŒγ€currentUser οΏ½?γ‚ˆγ†γͺ内部�?γƒ‡γƒΌγ‚ΏγŒε€‰ζ›΄γ•γ‚Œγ¦γ„γͺいγͺγ‚‰γ€ε†γƒ¬γƒ³γƒ€γƒΌγ™γ‚‹εΏ…θ¦γ―γ‚γ‚ŠγΎγ›γ‚“γ€‚γƒ‡γƒΌγ‚ΏγŒε€‰γ‚γ£γ¦γ„γͺいという事�?οΏ½γ‚’ React γŒζœ€ε€§ι™γ«ζ΄»η”¨γ§γγ‚‹γ‚ˆγ†γ«γ€login ι–’ζ•°γ‚’ useCallback でラップし、γ‚ͺγƒ–γ‚Έγ‚§γ‚―γƒˆοΏ½?η”Ÿζˆγ‚’ useMemo γ§γƒ©γƒƒγƒ—γ™γ‚‹γ“γ¨γŒγ§γγΎγ™γ€‚γ“γ‚Œγ―γƒ‘γƒ•γ‚©γƒΌγƒžγƒ³γ‚ΉοΏ½?ζœ€ι©εŒ–γ§γ™οΌš

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>
);
}

こ�?倉更�?η΅ζžœγ€MyApp γŒε†γƒ¬γƒ³γƒ€γƒΌγ™γ‚‹εΏ…θ¦γŒγ‚γ£γ¦γ‚‚γ€currentUser γŒε€‰ζ›΄γ•γ‚Œγ¦γ„γͺγ„ι™γ‚Šγ€useContext(AuthContext) γ‚’ε‘Όγ³ε‡Ίγ—γ¦γ„γ‚‹γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ‚’ε†γƒ¬γƒ³γƒ€γƒΌγ™γ‚‹εΏ…θ¦γ―γͺくγͺγ‚ŠγΎγ™γ€‚

詳しくは useMemo と useCallback を参照してください。


γƒˆγƒ©γƒ–γƒ«γ‚·γƒ₯ーティング

γƒ—γƒ­γƒγ‚€γƒ€γ«ζΈ‘γ—γŸε€€γŒθ‡ͺεˆ†οΏ½?γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ‹γ‚‰θ¦‹γˆγͺい

γ“γ‚ŒγŒθ΅·γ“γ‚‹δΈ€θˆ¬ηš„γͺη†η”±γ―γ„γγ€γ‹γ‚γ‚ŠγΎγ™οΌš

  1. useContext() γ‚’ε‘Όγ³ε‡Ίγ—γ¦γ„γ‚‹γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ¨εŒγ˜οΌˆγΎγŸγ―δΈ‹δ½οΏ½?οΌ‰γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ§ <SomeContext.Provider> をレンダーしている。<SomeContext.Provider> γ‚’ useContext() γ‚’ε‘Όγ³ε‡Ίγ™γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆοΏ½?ε€–ε΄γ‹γ€δΈŠδ½γ«η§»ε‹•γ—γ¦γγ γ•γ„γ€‚
  2. γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ‚’ <SomeContext.Provider> γ§γƒ©γƒƒγƒ—γ—εΏ˜γ‚Œγ¦γ„γ‚‹γ‹γ€γƒ„γƒͺγƒΌε†…οΏ½?思っている�?とは違う場所に配�?してしまっている。React DevTools を使ってツγƒͺγƒΌιšŽε±€γŒζ­£γ—γ„γ‹η’Ίθͺγ—てみてください。
  3. γƒ—γƒ­γƒγ‚€γƒ€γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ‹γ‚‰θ¦‹γŸ SomeContext γ¨γ€εˆ©η”¨ε΄οΏ½?γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ‹γ‚‰θ¦‹γŸ SomeContext γŒγ€γƒ“γƒ«γƒ‰γƒ„γƒΌγƒ«οΏ½?ε•ι‘Œγ«γ‚ˆγ‚Š 2 ぀�?η•°γͺγ‚‹γ‚ͺγƒ–γ‚Έγ‚§γ‚―γƒˆγ«γͺγ£γ¦γ„γ‚‹γ€‚γ“γ‚Œγ―δΎ‹γˆγ°γ€γ‚·γƒ³γƒœγƒͺックγƒͺγƒ³γ‚―γ‚’δ½Ώη”¨γ—γ¦γ„γ‚‹ε ΄εˆγͺγ©γ«η™Ίη”Ÿγ—γΎγ™γ€‚γ“γ‚Œγ‚’η’Ίθͺγ™γ‚‹γŸγ‚γ«γ€γγ‚Œγ‚‰γ‚’ window.SomeContext1 γ‚„ window.SomeContext2 οΏ½?γ‚ˆγ†γͺγ‚°γƒ­γƒΌγƒγƒ«ε€‰ζ•°γ«ε‰²γ‚Šε½“γ¦γ€γ‚³γƒ³γ‚½γƒΌγƒ«γ§ window.SomeContext1 === window.SomeContext2 γŒζˆγ‚Šη«‹γ€γ‹η’Ίθͺγ—γ¦γΏγ¦γγ γ•γ„γ€‚γ‚‚γ—εŒδΈ€γ§γͺいγͺら、ビルドツール�?レベルで、そ�?ε•ι‘Œγ‚’οΏ½?ζ­£γ™γ‚‹εΏ…θ¦γŒγ‚γ‚ŠγΎγ™γ€‚

ι•γ†γƒ‡γƒ•γ‚©γƒ«γƒˆε€€γ‚’ζŒ‡οΏ½?�している�?γ«γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆγ‹γ‚‰εΈΈγ« undefined γŒθΏ”γ£γ¦γγ‚‹

ツγƒͺγƒΌοΏ½?中に value οΏ½?γͺγ„γƒ—γƒ­γƒγ‚€γƒ€γŒγ‚γ‚‹οΏ½?γ‹γ‚‚γ—γ‚ŒγΎγ›γ‚“οΌš

// 🚩 Doesn't work: no value prop
<ThemeContext.Provider>
<Button />
</ThemeContext.Provider>

value γ‚’ζŒ‡οΏ½?οΏ½γ—εΏ˜γ‚ŒγŸε ΄εˆγ€γγ‚Œγ― value={undefined} を渑す�?γ¨εŒγ˜γ§γ™γ€‚

γΎγŸγ€θͺ€γ£γ¦ props として違う名前を使っている�?γ‹γ‚‚γ—γ‚ŒγΎγ›γ‚“οΌš

// 🚩 Doesn't work: prop should be called "value"
<ThemeContext.Provider theme={theme}>
<Button />
</ThemeContext.Provider>

どけら�?ε ΄εˆγ‚‚γ€React から�?θ­¦ε‘ŠγŒγ‚³γƒ³γ‚½γƒΌγƒ«γ«θ‘¨η€Ίγ•γ‚Œγ‚‹γ―γšγ§γ™γ€‚οΏ½?正するには、props として value γ‚’δ½Ώγ„γΎγ™οΌš

// βœ… Passing the value prop
<ThemeContext.Provider value={theme}>
<Button />
</ThemeContext.Provider>

createContext(defaultValue) γ§ζŒ‡οΏ½?οΏ½γ™γ‚‹γƒ‡γƒ•γ‚©γƒ«γƒˆε€€γ―γ€γƒ„γƒͺγƒΌοΏ½?δΈŠε΄γ«δΈ€θ‡΄γ™γ‚‹γƒ—γƒ­γƒγ‚€γƒ€γŒδΈ€εˆ‡ε­˜εœ¨γ—γͺγ„ε ΄εˆγ«οΏ½?γΏδ½Ώη”¨γ•γ‚Œγ‚‹γ“γ¨γ«ζ³¨ζ„γ—γ¦γγ γ•γ„γ€‚θ¦ͺοΏ½?ツγƒͺγƒΌοΏ½?どこかに <SomeContext.Provider value={undefined}> οΏ½?γ‚ˆγ†γͺγ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγŒγ‚γ‚Œγ°γ€useContext(SomeContext) γ‚’ε‘Όγ³ε‡Ίγ™γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ―γ‚³γƒ³γƒ†γ‚―γ‚Ήγƒˆε€€γ¨γ—γ¦γοΏ½? undefined γ‚’ε—γ‘ε–γ‚ŠγΎγ™γ€‚