---
source_hash: "d14800ef"
title: "Chapter 4: useContext"
weight: 430
---

# Chapter 4: useContext

## The Problem: Prop Drilling

When data needs to pass through multiple levels of components:

```javascript
function App() {
    const [user, setUser] = useState({ name: 'Jean' });

    return <Layout user={user} />;
}

function Layout({ user }) {
    return (
        <div>
            <Header user={user} />
            <Main user={user} />
        </div>
    );
}

function Header({ user }) {
    return <Navbar user={user} />;
}

function Navbar({ user }) {
    return <UserMenu user={user} />;  // Finally used here!
}

function UserMenu({ user }) {
    return <span>{user.name}</span>;
}
```

`Layout` and `Header` only forward `user` without using it. This is **prop drilling**.

## The Solution: Context

Context allows you to "teleport" data through the component tree.

### Step 1: Create the Context

```javascript
import { createContext } from 'react';

const UserContext = createContext(null);
```

### Step 2: Provide the Value (Provider)

```javascript
function App() {
    const [user, setUser] = useState({ name: 'Jean' });

    return (
        <UserContext.Provider value={user}>
            <Layout />
        </UserContext.Provider>
    );
}
```

### Step 3: Consume the Value (useContext)

```javascript
import { useContext } from 'react';

function UserMenu() {
    const user = useContext(UserContext);

    return <span>{user.name}</span>;
}
```

Intermediate components no longer need to pass `user`:

```javascript
function Layout() {
    return (
        <div>
            <Header />
            <Main />
        </div>
    );
}

function Header() {
    return <Navbar />;
}

function Navbar() {
    return <UserMenu />;
}
```

## Complete Example: Theme

```javascript
// ThemeContext.js
import { createContext, useContext, useState } from 'react';

const ThemeContext = createContext(null);

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

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

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

export function useTheme() {
    const context = useContext(ThemeContext);
    if (!context) {
        throw new Error('useTheme must be used within ThemeProvider');
    }
    return context;
}
```

```javascript
// App.js
import { ThemeProvider } from './ThemeContext';

function App() {
    return (
        <ThemeProvider>
            <Layout />
        </ThemeProvider>
    );
}
```

```javascript
// ThemeToggle.js
import { useTheme } from './ThemeContext';

function ThemeToggle() {
    const { theme, toggleTheme } = useTheme();

    return (
        <button onClick={toggleTheme}>
            Current mode: {theme}
        </button>
    );
}
```

```javascript
// Card.js
import { useTheme } from './ThemeContext';

function Card({ children }) {
    const { theme } = useTheme();

    return (
        <div className={`card card-${theme}`}>
            {children}
        </div>
    );
}
```

## Passing Functions via Context

You can pass functions to allow children to modify the state:

```javascript
const AuthContext = createContext(null);

function AuthProvider({ children }) {
    const [user, setUser] = useState(null);

    const login = async (credentials) => {
        const response = await api.login(credentials);
        setUser(response.user);
    };

    const logout = () => {
        setUser(null);
    };

    return (
        <AuthContext.Provider value={{ user, login, logout }}>
            {children}
        </AuthContext.Provider>
    );
}

function useAuth() {
    return useContext(AuthContext);
}

// Usage
function LoginButton() {
    const { user, login, logout } = useAuth();

    if (user) {
        return <button onClick={logout}>Logout</button>;
    }

    return <button onClick={() => login({ email, password })}>Login</button>;
}
```

## When to Use Context?

**Good use cases:**

- Theme (dark/light mode)
- Logged in user
- Language / internationalization
- Global configuration

**Bad use cases:**

- Local form state
- Data that concerns only a few nearby components
- State that changes very frequently (performance)

## Context vs Props

| Criteria | Props | Context |
| --- | --- | --- |
| Data concerns few components | ✅ | ❌ |
| Data passes through many levels | ❌ | ✅ |
| Explicit data flow | ✅ | ❌ |
| Global configuration | ❌ | ✅ |

## Multiple Contexts

You can nest multiple Providers:

```javascript
function App() {
    return (
        <AuthProvider>
            <ThemeProvider>
                <LanguageProvider>
                    <Layout />
                </LanguageProvider>
            </ThemeProvider>
        </AuthProvider>
    );
}
```

## Exercises

### Exercise 1: Language Context

Create a context to manage language (fr/en) with a button to change it.

**Solution:**

```javascript
// LanguageContext.js
import { createContext, useContext, useState } from 'react';

const LanguageContext = createContext(null);

const translations = {
    fr: { greeting: 'Bonjour', button: 'English' },
    en: { greeting: 'Hello', button: 'French' }
};

export function LanguageProvider({ children }) {
    const [lang, setLang] = useState('fr');

    const toggleLang = () => {
        setLang(prev => prev === 'fr' ? 'en' : 'fr');
    };

    const t = (key) => translations[lang][key];

    return (
        <LanguageContext.Provider value={{ lang, toggleLang, t }}>
            {children}
        </LanguageContext.Provider>
    );
}

export function useLanguage() {
    return useContext(LanguageContext);
}
```

```javascript
// Greeting.js
function Greeting() {
    const { t, toggleLang } = useLanguage();

    return (
        <div>
            <h1>{t('greeting')}</h1>
            <button onClick={toggleLang}>{t('button')}</button>
        </div>
    );
}
```

## Key Points to Remember

1. **Context** avoids prop drilling
2. **createContext** -> **Provider** -> **useContext**
3. Create a **custom hook** (useTheme, useAuth) to simplify usage
4. Use for **truly global** data
5. Don't overuse: props are often clearer

## Module 3 Summary

| Hook | Usage | Triggers Re-render |
| --- | --- | --- |
| useState | Local state | Yes |
| useEffect | Side effects (API, events) | No (but can modify state) |
| useRef | DOM and persistent values | No |
| useContext | Global data | Yes (if value changes) |

[<- Previous Chapter](/training/module3-hooks-fondamentaux/useref) | [Back to module](/training/module3-hooks-fondamentaux) | [Next Module: Advanced React ->](/training/module4-react-avance)
