How to share state between components in React

Sharing state between components in React enables data synchronization and communication across different parts of your application through various state management patterns. As the creator of CoreUI, a widely used open-source UI library, I’ve implemented state sharing patterns in thousands of React applications for dashboard widgets, form management, and component synchronization. From my expertise, the most effective approach is using lifted state for simple cases and Context API for complex shared state scenarios. This method provides clean data flow with proper state encapsulation and efficient re-rendering patterns.

Use lifted state for simple sharing and Context API for complex state that needs to be accessed by multiple components.

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

// Method 1: Lifting State Up
function App() {
  const [sharedData, setSharedData] = useState({ count: 0, user: null })

  return (
    <div>
      <Header user={sharedData.user} />
      <Counter
        count={sharedData.count}
        onUpdate={(count) => setSharedData(prev => ({ ...prev, count }))}
      />
      <UserProfile
        user={sharedData.user}
        onUserChange={(user) => setSharedData(prev => ({ ...prev, user }))}
      />
    </div>
  )
}

// Method 2: Context API for Complex State
const AppStateContext = createContext()

function AppStateProvider({ children }) {
  const [state, setState] = useState({
    user: null,
    theme: 'light',
    notifications: []
  })

  const updateUser = (user) => {
    setState(prev => ({ ...prev, user }))
  }

  const addNotification = (notification) => {
    setState(prev => ({
      ...prev,
      notifications: [...prev.notifications, notification]
    }))
  }

  return (
    <AppStateContext.Provider value={{ state, updateUser, addNotification }}>
      {children}
    </AppStateContext.Provider>
  )
}

// Custom hook for consuming context
function useAppState() {
  const context = useContext(AppStateContext)
  if (!context) {
    throw new Error('useAppState must be used within AppStateProvider')
  }
  return context
}

// Using shared state in components
function UserComponent() {
  const { state, updateUser } = useAppState()

  return (
    <div>
      <p>User: {state.user?.name || 'Not logged in'}</p>
      <button onClick={() => updateUser({ name: 'John Doe' })}>
        Login
      </button>
    </div>
  )
}

For simple state sharing between a few components, lift state to the nearest common ancestor and pass data down via props. For complex state accessed by many components, use Context API with custom hooks for clean consumption. This provides efficient re-rendering and clear data flow patterns.

Best Practice Note:

This is the same state sharing architecture we use in CoreUI React components for dashboard state management and component communication across complex interfaces.


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