How to use Context API in React

React Context API provides a way to share data across components without passing props down through every level, eliminating prop drilling and creating clean global state management. As the creator of CoreUI, a widely used open-source UI library, I’ve implemented Context API in thousands of React applications for theme management, user authentication, and global application state. From my expertise, the most effective approach is creating context with custom providers and hooks for type-safe consumption and optimal performance. This method provides clean global state access with efficient re-rendering and maintainable code architecture.

Create context with createContext, provide values with Provider, and consume with useContext hook.

import { createContext, useContext, useState, useReducer } from 'react'

// Create Theme Context
const ThemeContext = createContext()

function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light')

  const toggleTheme = () => {
    setTheme(prevTheme => prevTheme === 'light' ? 'dark' : 'light')
  }

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  )
}

// Custom hook for consuming theme context
function useTheme() {
  const context = useContext(ThemeContext)
  if (!context) {
    throw new Error('useTheme must be used within ThemeProvider')
  }
  return context
}

// User Context with useReducer for complex state
const UserContext = createContext()

const userReducer = (state, action) => {
  switch (action.type) {
    case 'LOGIN':
      return { ...state, user: action.payload, isAuthenticated: true }
    case 'LOGOUT':
      return { ...state, user: null, isAuthenticated: false }
    case 'UPDATE_PROFILE':
      return { ...state, user: { ...state.user, ...action.payload } }
    default:
      return state
  }
}

function UserProvider({ children }) {
  const [state, dispatch] = useReducer(userReducer, {
    user: null,
    isAuthenticated: false
  })

  return (
    <UserContext.Provider value={{ state, dispatch }}>
      {children}
    </UserContext.Provider>
  )
}

// App component with providers
function App() {
  return (
    <ThemeProvider>
      <UserProvider>
        <Header />
        <MainContent />
      </UserProvider>
    </ThemeProvider>
  )
}

// Components consuming context
function Header() {
  const { theme, toggleTheme } = useTheme()
  const { state } = useContext(UserContext)

  return (
    <header className={`header-${theme}`}>
      <h1>Welcome {state.user?.name}</h1>
      <button onClick={toggleTheme}>
        Switch to {theme === 'light' ? 'dark' : 'light'} mode
      </button>
    </header>
  )
}

Context provides values through Provider components and consumes them via useContext hook. Create custom hooks for clean context consumption and error handling. Use useReducer for complex state logic and useState for simple shared values. Wrap your app with providers to make context available to child components.

Best Practice Note:

This is the same Context API architecture we use in CoreUI React components for theme management, authentication state, and global configuration across dashboard applications.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author

Subscribe to our newsletter
Get early information about new products, product updates and blog posts.

Answers by CoreUI Core Team