React Mastery / Advanced React Hooks

Context Example

👀 The "Auth Context" Example

In a real-world scenario, you don't just want to pass data; you also want to pass functions (like login and logout) so that child components can update the global state.

1. The Context Setup (AuthContext.js)

We bundle the state and the logic into a single "Wrapper" component.

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

// 1. Initialize the Context
const AuthContext = createContext();

// 2. Create a custom Provider component
export function AuthProvider({ children }) {
  const [user, setUser] = useState(null);

  const login = (userData) => setUser(userData);
  const logout = () => setUser(null);

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

// 3. Custom hook for easier consumption
export const useAuth = () => useContext(AuthContext);

2. The App Entry Point (App.js)

Wrap your entire application so the "Auth" state is available everywhere.

import { AuthProvider } from './AuthContext';

function App() {
  return (
    <AuthProvider>
      <Navbar />
      <ProfilePage />
    </AuthProvider>
  );
}

3. The Consumer Component (Navbar.js)

Notice how we don't pass any props to <Navbar />. It simply "grabs" what it needs from the context.

import { useAuth } from './AuthContext';

function Navbar() {
  const { user, logout } = useAuth();

  return (
    <nav>
      {user ? (
        <>
          <span>Welcome, {user.name}!</span>
          <button onClick={logout}>Logout</button>
        </>
      ) : (
        <span>Please log in</span>
      )}
    </nav>
  );
}

👉 Visualizing the Data Flow

In this setup:

  • The Provider acts as a radio station broadcasting the user status and login/logout functions.

  • The Navbar (and any other component) acts as a radio receiver, tuning into the AuthContext frequency.

  • Prop Drilling is avoided entirely; the App component doesn't need to manually pass the user object down to every single link or button.

🧠 Code Explanation (Navbar)

  • Importing the "Radio Frequency": By importing useAuth, the component is getting ready to "tune in" to the authentication data we set up earlier.

  • Destructuring State: The line const { user, logout } = useAuth(); extracts exactly what the Navbar needs: the current user's info (user) and the function to sign them out (logout).

  • Conditional Rendering: It uses a Ternary Operator (user ? ... : ...) to check if a user is logged in.

    • If user exists: It displays a personalized greeting ("Welcome, Jane!") and a logout button.

    • If user is null: It simply displays "Please log in."

  • Direct Interaction: The onClick={logout} connects the button directly to the global logout logic defined in your Context Provider, bypassing the need to pass functions down through props.

  • Automatic Updates: If the user logs out elsewhere in the app, this Navbar will automatically re-render and switch back to the "Please log in" view because it is "subscribed" to the Context.


🤝 Key Takeaways for Real-Life Usage

  • Custom Hooks: Notice the useAuth hook created in step 1. This is a standard industry practice. It makes your code cleaner and prevents you from having to import both useContext and AuthContext in every file.

  • Initial Value: Always keep your createContext() default value empty or null if the data is fetched dynamically.

  • The "Double Render" Caution: If your value in the Provider is an object created on the fly (e.g., value={{ user, login }}), it technically creates a new object on every render. For massive apps, you'd wrap that object in useMemo.