[React] What is Context API?

·

3 min read

[React] What is Context API?

In React, Context provides a way to pass data through the component tree without having to pass props manually at every level. It allows you to share values across the entire application effortlessly. It enables components to subscribe to a context and access its value anywhere in the component tree, regardless of how deep the component is nested.


When to Use Context?

Context is useful in scenarios where certain data needs to be accessed by many components at different levels of the component tree.

  • Problems that can occur when data is delivered only by Props

      function App() {
        return <GrandParent value="Hello World!" />;
      }
    
      function GrandParent({ value }) {
        return <Parent value={value} />;
      }
    
      function Parent({ value }) {
        return <Child value={value} />;
      }
    
      function Child({ value }) {
        return <GrandChild value={value} />;
      }
    
      function GrandChild({ value }) {
        return <Message value={value} />;
      }
    
      function Message({ value }) {
        return <div>Received: {value}</div>;
      }
    

    These codes are called Props Drilling. It's okay to pass Props through one or two components, but it's going to be inconvenient to pass through four like this. For example, if you're trying to open a Message component and figure out where this value is coming from, it's very inefficient because you have to keep riding back to that parent component.

  • Problems solved with using Context

      import { createContext, useContext } from 'react';
      const MyContext = createContext();
    
      function App() {
        return (
          <MyContext.Provider value="Hello World">
            <GrandParent />
          </MyContext.Provider>
        );
      }
    
      function GrandParent() {
        return <Parent />;
      }
    
      function Parent() {
        return <Child />;
      }
    
      function Child() {
        return <GrandChild />;
      }
    
      function GrandChild() {
        return <Message />;
      }
    
      function Message() {
        const value = useContext(MyContext);
        return <div>Received: {value}</div>;
      }
    

    This way, you can erase the props that you were delivering through multiple components in the middle.


How to use Context?

  1. Call createContext outside of any components to create a context.

  2. The Context object contains a component called Provider, and if you set the value you want to share between the components, the child components can access it immediately.

  3. Call useContext at the top level of your component to read and subscribe to context.

  • Example 1 (value is string)

      import { createContext, useContext } from 'react';
    
      // 1. Creat context
      const ThemeContext = createContext(null);
    
      export default function MyApp() {
        return (
          // 2. Provide context
          <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 }) {
        // 3. Consume context
        const theme = useContext(ThemeContext);
        const className = 'panel-' + theme;
        return (
          <section className={className}>
            <h1>{title}</h1>
            {children}
          </section>
        )
      }
    
      function Button({ children }) {
        // 3. Consume context
        const theme = useContext(ThemeContext);
        const className = 'button-' + theme;
        return (
          <button className={className}>
            {children}
          </button>
        );
      }
    
  • Example 2 (value is object and changeable)

      // ThemeContext.js
      import { createContext, useState } from 'react';
    
      // 1. Creat context
      const ThemeContext = createContext();
    
      export const ThemeProvider = ({ children }) => {
        const [theme, setTheme] = useState('light');
    
        const toggleTheme = () => {
          setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light'));
        };
    
        return (
          // 2. Provide context
          <ThemeContext.Provider value={{ theme, toggleTheme }}>
            {children}
          </ThemeContext.Provider>
        );
      };
    
      export default ThemeContext;
    
      // App.js
      import { ThemeProvider } from './ThemeContext';
      import Header from './Header';
      import Button from './Button';
    
      function App() {
        return (
          <ThemeProvider>
            <Header />
            <Button />
          </ThemeProvider>
        );
      }
    
      export default App;
    
      // Header.js
      import { useContext } from 'react';
      import ThemeContext from './ThemeContext';
    
      function Header() {
        // 3. Consume context
        const { theme } = useContext(ThemeContext);
        return <header style={{ backgroundColor: theme }}>Header</header>;
      }
    
      export default Header;
    
      // Button.js
      import { useContext } from 'react';
      import ThemeContext from './ThemeContext';
    
      function Button() {
        // 3. Consume context
        const { toggleTheme } = useContext(ThemeContext);
        return <button onClick={toggleTheme}>Toggle Theme</button>;
      }
    
      export default Button;