비공식 사이트. 24.12.31. 폐쇄예정
공식사이트 바로가기

useContext is a React Hook that lets you read and subscribe to context from your component. useContext는 컴포넌트에서 context를 읽고 구독할 수 있게 해주는 React Hook입니다.

const value = useContext(SomeContext)

Reference참조

useContext(SomeContext)

Call useContext at the top level of your component to read and subscribe to context. 컴포넌트의 최상위 레벨에서 useContext를 호출하여 context를 읽고 구독합니다.

import { useContext } from 'react';

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

See more examples below. 아래에서 더 많은 예시를 확인하세요.

Parameters매개변수

  • SomeContext: The context that you’ve previously created with createContext. The context itself does not hold the information, it only represents the kind of information you can provide or read from components. context: 이전에 createContext로 생성한 context입니다. context 자체는 정보를 보유하지 않으며, 컴포넌트에서 제공하거나 읽을 수 있는 정보의 종류를 나타낼 뿐입니다.

Returns반환값

useContext returns the context value for the calling component. It is determined as the value passed to the closest SomeContext.Provider above the calling component in the tree. If there is no such provider, then the returned value will be the defaultValue you have passed to createContext for that context. The returned value is always up-to-date. React automatically re-renders components that read some context if it changes. useContext는 호출하는 컴포넌트에 대한 context 값을 반환합니다. 이 값은 호출한 컴포넌트에서 트리상 위에 있는 가장 가까운 SomeContext.Provider에 전달된 value입니다. 이러한 provider가 없는 경우 반환되는 값은 해당 context에 대해 createContext에 전달한 defaultValue가 됩니다. 반환된 값은 항상 최신 값입니다. React는 context가 변경되면 context를 읽는 컴포넌트를 자동으로 리렌더링합니다.

Caveats주의사항

  • useContext() call in a component is not affected by providers returned from the same component. The corresponding <Context.Provider> needs to be above the component doing the useContext() call. 컴포넌트의 useContext() 호출은 동일한 컴포넌트에서 반환된 provider의 영향을 받지 않습니다. 해당 <Context.Provider>는 반드시 useContext() 호출을 수행하는 컴포넌트의 에 있어야 합니다.

  • React automatically re-renders all the children that use a particular context starting from the provider that receives a different value. The previous and the next values are compared with the Object.is comparison. Skipping re-renders with memo does not prevent the children receiving fresh context values. React는 변경된 value를 받는 provider부터 시작해서 해당 context를 사용하는 자식들에 대해서까지 전부 자동으로 리렌더링합니다. 이전 값과 다음 값은 Object.is로 비교합니다. memo로 리렌더링을 건너뛰어도 새로운 context 값을 수신하는 자식들을 막지는 못합니다.

  • If your build system produces duplicates modules in the output (which can happen with symlinks), this can break context. Passing something via context only works if SomeContext that you use to provide context and SomeContext that you use to read it are exactly the same object, as determined by a === comparison. 빌드 시스템이 출력 결과에 중복 모듈을 생성하는 경우(심볼릭 링크를 사용하는 경우 발생할 수 있음) context가 손상될 수 있습니다. context를 통해 무언가를 전달하는 것은 === 비교에 의해 결정되는 것처럼 context를 제공하는 데 사용하는 SomeContext와 context를 읽는 데 사용하는 SomeContext정확하게 동일한 객체인 경우에만 작동합니다.


Usage사용법

Passing data deeply into the tree트리 깊숙이 데이터 전달하기

Call useContext at the top level of your component to read and subscribe to context. 컴포넌트의 최상위 레벨에서 useContext를 호출하여 context를 읽고 구독합니다.

import { useContext } from 'react';

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

useContext returns the context value for the context you passed. To determine the context value, React searches the component tree and finds the closest context provider above for that particular context. useContext는 전달한context에 대한 context 값을 반환합니다. context 값을 결정하기 위해 React는 컴포넌트 트리를 검색하고 특정 context에 대해 위에서 가장 가까운 context provider를 찾습니다.

To pass context to a Button, wrap it or one of its parent components into the corresponding context provider: context를 Button에 전달하려면 해당 버튼 또는 상위 컴포넌트 중 하나를 해당 context provider로 감쌉니다:

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

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

It doesn’t matter how many layers of components there are between the provider and the Button. When a Button anywhere inside of Form calls useContext(ThemeContext), it will receive "dark" as the value. provider와 Button 사이에 얼마나 많은 컴포넌트 레이어가 있는지는 중요하지 않습니다. Form내부의ButtonuseContext(ThemeContext)를 호출하면 "dark"를 값으로 받습니다.

Pitfall | 함정

useContext() always looks for the closest provider above the component that calls it. It searches upwards and does not consider providers in the component from which you’re calling useContext(). useContext()는 항상 그것을 호출하는 컴포넌트 의 가장 가까운 provider를 찾습니다. useContext()를 호출하는 컴포넌트 내의 provider는 고려하지 않습니다.

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


Updating data passed via contextcontext를 통해 전달된 데이터 업데이트하기

Often, you’ll want the context to change over time. To update context, combine it with state. Declare a state variable in the parent component, and pass the current state down as the context value to the provider. 시간이 지남에 따라 context가 변경되기를 원하는 경우가 종종 있습니다. context를 업데이트하려면 state와 결합해야 합니다. 부모 컴포넌트에 state 변수를 선언하고 현재 state를 context 값으로 provider에 전달합니다.

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

Now any Button inside of the provider will receive the current theme value. If you call setTheme to update the theme value that you pass to the provider, all Button components will re-render with the new 'light' value. 이제 provider 내부의 모든 Button은 현재 theme 값을 받게 됩니다. provider에게 전달한 theme 값을 업데이트하기 위해 setTheme를 호출하면 모든 Button 컴포넌트가 새로운 light 값으로 리렌더링됩니다.

Examples of updating contextcontext 업데이트 예시

Example 1 of 5: Updating a value via contextcontext를 통해 값 업데이트하기

In this example, the MyApp component holds a state variable which is then passed to the ThemeContext provider. Checking the “Dark mode” checkbox updates the state. Changing the provided value re-renders all the components using that context. 이 예제에서 MyApp 컴포넌트는 state 변수를 보유하고 있으며, 이 state 변수는 ThemeContext provider로 전달됩니다. “Dark mode” 체크박스를 선택하면 state가 업데이트됩니다. 제공된 값을 변경하면 해당 context를 사용하는 모든 컴포넌트가 리렌더링됩니다.

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

Note that value="dark" passes the "dark" string, but value={theme} passes the value of the JavaScript theme variable with JSX curly braces. Curly braces also let you pass context values that aren’t strings. value="dark""dark"문자열을 전달하지만 value={theme}JSX 중괄호를 사용하여 JavaScript theme 변수 값을 전달합니다. 중괄호를 사용하면 문자열이 아닌 context 값도 전달할 수 있습니다.


Specifying a fallback default valuefallback 기본값 지정하기

If React can’t find any providers of that particular context in the parent tree, the context value returned by useContext() will be equal to the default value that you specified when you created that context: React가 부모 트리에서 특정 context의 provider들을 찾을 수 없는 경우, useContext()가 반환하는 context 값은 해당 context를 생성할 때 지정한 기본값과 동일합니다:

const ThemeContext = createContext(null);

The default value never changes. If you want to update context, use it with state as described above. 기본값은 절대 변경되지 않습니다. context를 업데이트하려면 앞서 설명된 대로 state를 사용하세요.

Often, instead of null, there is some more meaningful value you can use as a default, for example: null 대신 기본값으로 사용할 수 있는 더 의미 있는 값이 있는 경우가 많습니다, 예를 들어:

const ThemeContext = createContext('light');

This way, if you accidentally render some component without a corresponding provider, it won’t break. This also helps your components work well in a test environment without setting up a lot of providers in the tests. 이렇게 하면 실수로 해당 provider 없이 일부 컴포넌트를 렌더링해도 중단되지 않습니다. 또한 테스트 환경에서 많은 provider를 설정하지 않고도 컴포넌트가 테스트 환경에서 잘 작동하는 데 도움이 됩니다.

In the example below, the “Toggle theme” button is always light because it’s outside any theme context provider and the default context theme value is 'light'. Try editing the default theme to be 'dark'. 아래 예시에서 ‘테마 전환’ 버튼은 테마 context provider 외부에 있고 기본 context 테마 값이 '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>
  );
}


Overriding context for a part of the tree트리 일부에 대한 context 재정의하기

You can override the context for a part of the tree by wrapping that part in a provider with a different value. 트리의 일부분을 다른 값의 provider로 감싸 해당 부분에 대한 context를 재정의할 수 있습니다.

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

You can nest and override providers as many times as you need. 필요한 만큼 provider들을 중첩하고 재정의할 수 있습니다.

Examples of overriding contextcontext 재정의 예시

Example 1 of 2: Overriding a theme테마 재정의하기

Here, the button inside the Footer receives a different context value ("light") than the buttons outside ("dark"). 여기서 Footer 안쪽의 버튼은 바깥쪽의 버튼(”dark”)과 다른 context 값(”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>
  );
}


Optimizing re-renders when passing objects and functions객체 및 함수 전달 시 리렌더링 최적화

You can pass any values via context, including objects and functions. context를 통해 객체와 함수를 포함한 모든 값을 전달할 수 있습니다.

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

Here, the context value is a JavaScript object with two properties, one of which is a function. Whenever MyApp re-renders (for example, on a route update), this will be a different object pointing at a different function, so React will also have to re-render all components deep in the tree that call useContext(AuthContext). 여기서 context 값은 두 개의 프로퍼티를 가진 JavaScript 객체이며, 그 중 하나는 함수입니다. MyApp이 리렌더링할 때마다(예: 라우트 업데이트), 이것은 다른 함수를 가리키는 다른 객체가 될 것이므로 React는 useContext(AuthContext)를 호출하는 트리 깊숙한 곳의 모든 컴포넌트도 리렌더링해야 합니다.

In smaller apps, this is not a problem. However, there is no need to re-render them if the underlying data, like currentUser, has not changed. To help React take advantage of that fact, you may wrap the login function with useCallback and wrap the object creation into useMemo. This is a performance optimization: 소규모 앱에서는 문제가 되지 않습니다. 그러나 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>
);
}

As a result of this change, even if MyApp needs to re-render, the components calling useContext(AuthContext) won’t need to re-render unless currentUser has changed. 이 변경으로 인해 MyApp이 리렌더링해야 하는 경우에도 currentUser가 변경되지 않는 한 useContext(AuthProvider)를 호출하는 컴포넌트는 리렌더링할 필요가 없습니다.

Read more about useMemo and useCallback. useMemouseCallback에 대해 더 읽어보세요.


Troubleshooting문제 해결

My component doesn’t see the value from my provider컴포넌트가 provider의 값을 인식하지 못합니다

There are a few common ways that this can happen: 이런 일이 발생하는 몇 가지 일반적인 경우가 있습니다:

  1. You’re rendering <SomeContext.Provider> in the same component (or below) as where you’re calling useContext(). Move <SomeContext.Provider> above and outside the component calling useContext(). <SomeContext.Provider>useContext()를 호출하는 컴포넌트 위와 외부로 이동합니다.

  2. You may have forgotten to wrap your component with <SomeContext.Provider>, or you might have put it in a different part of the tree than you thought. Check whether the hierarchy is right using React DevTools. 컴포넌트를 <SomeContext.Provider>로 감싸는 것을 잊었거나 생각했던 것과 다른 트리 부분에 넣었을 수 있습니다. React DevTools를 사용하여 계층 구조가 올바른지 확인하세요.

  3. You might be running into some build issue with your tooling that causes SomeContext as seen from the providing component and SomeContext as seen by the reading component to be two different objects. This can happen if you use symlinks, for example. You can verify this by assigning them to globals like window.SomeContext1 and window.SomeContext2 and then checking whether window.SomeContext1 === window.SomeContext2 in the console. If they’re not the same, fix that issue on the build tool level. 제공하는 컴포넌트에서 보는 SomeContext 와 읽는 컴포넌트에서 보는 SomeContext가 서로 다른 두 개의 객체가 되는 빌드 문제가 발생할 수 있습니다. 예를 들어, 심볼릭 링크를 사용하는 경우 이런 문제가 발생할 수 있습니다. 이를 확인하려면 window.SomeContext1window.SomeContext2와 같이 전역에 할당하고 콘솔에서 window.SomeContext1 === window.SomeContext2인지 확인하면 됩니다. 동일하지 않은 경우 빌드 도구 수준에서 해당 문제를 해결해야 합니다.

I am always getting undefined from my context although the default value is different기본값이 다른데도 context에서 항상 undefined만 얻습니다

You might have a provider without a value in the tree: 트리에 value가 없는 provider가 있을 수 있습니다:

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

If you forget to specify value, it’s like passing value={undefined}. value를 지정하는 것을 잊어버리면 value={undefined}를 전달하는 것과 같습니다.

You may have also mistakingly used a different prop name by mistake: 실수로 다른 prop 명을 사용했을 수도 있습니다:

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

In both of these cases you should see a warning from React in the console. To fix them, call the prop value: 이 두 가지 경우 모두 콘솔에서 React 경고가 표시될 것입니다. 이를 수정하려면 value prop을 호출하세요:

// ✅ Passing the value prop
<ThemeContext.Provider value={theme}>
<Button />
</ThemeContext.Provider>

Note that the default value from your createContext(defaultValue) call is only used if there is no matching provider above at all. If there is a <SomeContext.Provider value={undefined}> component somewhere in the parent tree, the component calling useContext(SomeContext) will receive undefined as the context value. createContext(defaultValue) 호출의 기본값은 오직 위쪽에 일치하는 provider가 전혀 없는 경우에만 적용된다는 점에 유의하세요. 부모 트리 어딘가에 <SomeContext.Provider value={undefined}> 컴포넌트가 있는 경우, useContext(SomeContext)를 호출하는 컴포넌트는 undefined를 context 값으로 받습니다.