Skip to content

Step 5: Understanding Context API

Time: ~5 minutes | Type: Learning | Concepts: React Context, Global State, Prop Drilling

What This Step Is About

Before we build authentication features, you need to understand React Context — the pattern we'll use to make auth state available throughout our app.

Interactive Learning

💡 Ask AI to Teach You:

Copy this prompt into Claude and read the response carefully:

I'm learning React Context API. Can you explain:

1. What is "prop drilling" and why is it a problem?
2. What is React Context and how does it solve prop drilling?
3. What is a Provider and what does it do?
4. What is a custom hook and why would we create one for auth?

Use a simple analogy — I'm a beginner.

What You Should Learn

After AI explains, you should be able to answer these questions:

  • What is prop drilling? (Passing props through many components that don't need them)
  • What is React Context? (A way to share data without passing props)
  • What is a Provider? (Component that makes data available to its children)
  • What is a Consumer? (Component or hook that uses the provided data)

If AI's explanation didn't cover these points, ask follow-up questions like:

  • "Can you show me an example of prop drilling?"
  • "How does Context work differently from just passing props?"

The Problem: Prop Drilling

Let's visualize why we need Context for auth:

Without Context (Prop Drilling):

App (has user state)
 ├─ Layout (doesn't need user, just passes it down)
 │   ├─ Navigation (NEEDS user to show/hide logout button)
 │   └─ Main
 │       └─ Dashboard (NEEDS user to display name)
 └─ LoginPage (NEEDS user to redirect if already logged in)

Every component in the chain needs to accept and pass the user prop, even if it doesn't use it!

With Context (Direct Access):

AuthProvider (has user state)
 └─ App
     ├─ Layout
     │   ├─ Navigation (useAuth() → gets user directly!)
     │   └─ Main
     │       └─ Dashboard (useAuth() → gets user directly!)
     └─ LoginPage (useAuth() → gets user directly!)

Any component can get user directly by calling useAuth(). No prop drilling!

How Context Works for Auth

We'll create three things:

1. AuthContext (the tunnel)

  • Creates a "tunnel" through the component tree
  • Defines what data is available (user, signIn, signOut, etc.)

2. AuthProvider (the broadcaster)

  • Component that wraps your app
  • Holds the auth state (current user, loading status)
  • Provides auth functions (signIn, signOut, signUp)
  • Listens to Firebase for auth changes

3. useAuth Hook (the receiver)

  • Custom hook components use to access auth
  • Returns: { user, signIn, signOut, signUp, loading }
  • Cleaner than using Context directly

Real-World Analogy

Think of Context like a radio station:

AuthProvider (Radio Station):

  • Broadcasts the signal (auth state)
  • Updates when things change (user logs in/out)

AuthContext (Radio Frequency):

  • The frequency/channel everything uses
  • Defined once, used everywhere

useAuth Hook (Radio Receiver):

  • Any component can "tune in" to get the signal
  • Just call useAuth() to receive current auth state

Components don't need to pass "radio signals" to each other — they just tune in directly!

Why We Need This for Auth

Authentication has unique requirements:

Auth state is global:

  • Navigation needs to know: show Login or Logout?
  • Dashboard needs to know: who is the current user?
  • ProtectedRoute needs to know: is user authenticated?

Auth state changes:

  • User logs in → all components need to update
  • User logs out → all components need to update
  • User refreshes page → need to restore auth state

Without Context, you'd have to:

  • Pass user prop through every component
  • Pass signIn, signOut functions through every component
  • Manually update every component when auth changes
  • Duplicate auth logic in multiple places

With Context:

  • Wrap app once with <AuthProvider>
  • Any component calls useAuth() to get current state
  • Provider automatically updates all consumers
  • Auth logic lives in one place

Check Your Understanding

Before moving to the next step, you should be able to explain:

  • [ ] What prop drilling is and why it's problematic
  • [ ] How Context solves prop drilling
  • [ ] What a Provider does
  • [ ] What a custom hook like useAuth() provides
  • [ ] Why auth state should be global

Visual: Our Auth Architecture

App.tsx
└─ <AuthProvider>  ← Holds auth state, provides functions
    └─ <BrowserRouter>
        └─ <Layout>
            ├─ <Navigation />  ← Calls useAuth() to show/hide buttons
            └─ <Routes>
                ├─ /login → <LoginPage />  ← Calls useAuth().signIn()
                ├─ /register → <RegisterPage />  ← Calls useAuth().signUp()
                └─ /dashboard → <DashboardPage />  ← Calls useAuth().user

Key insight: Any component nested inside <AuthProvider> can call useAuth() to get current auth state and functions!

Next Step

Now that you understand the "why," let's build the AuthContext:

Step 6: Create Auth Context →

Built for learning | Open source on GitHub