3

Client-Side Rendering (CSR)

Render in the browser for interactive components and real-time updates

Intermediate

What It Does

  • Client-side rendering
    The "use client" directive tells Next.js that this React component should run in the browser (client-side) instead of on the server.
  • Browser-only APIs
    Components marked with "use client" can use browser-only APIs and React hooks like useState and useEffect.
  • Hydration
    The initial HTML is sent from the server, but all interactivity and dynamic updates happen in the browser.

Why We Use It

  • Browser URL Access
    Uses useSearchParams() to read error parameters from the URL
  • Interactive State Management
    Uses useState(false) to track loading states during sign-in
  • NextAuth Client Functions
    Calls signIn() which requires browser context for OAuth flows
  • Dynamic Provider Loading
    Uses useProvider(providerKey) hook that fetches provider data client-side
  • User Click Handlers
    Has onClick={handleSignIn} events that need browser interaction
  • Real-time Error Display
    Shows dynamic error messages based on URL parameters
  • Loading States
    Updates UI in real-time during authentication process
  • OAuth Redirects
    Handles authentication callbacks that require browser navigation

How it works

  1. 1
    Server sends initial HTML

    Basic structure without interactivity

  2. 2
    Browser downloads JavaScript

    React bundle loads in the browser

  3. 3
    React hydrates the page

    Attaches event handlers and state

  4. 4
    Component becomes interactive

    Users can click, type, and interact

  5. 5
    Updates happen in browser

    No server required for interactions

Code

'use client' // This directive makes it a Client Component

import { useState } from 'react'
import { useSearchParams } from 'next/navigation'
import { signIn } from 'next-auth/react'

export default function LoginForm() {
  // Browser-only hooks
  const [isLoading, setIsLoading] = useState(false)
  const searchParams = useSearchParams()
  const error = searchParams.get('error')

  // Browser-only event handler
  const handleSignIn = async (provider: string) => {
    setIsLoading(true)
    await signIn(provider, { callbackUrl: '/dashboard' })
  }

  return (
    <div>
      {error && (
        <div className="error">
          Authentication failed: {error}
        </div>
      )}
      
      <button 
        onClick={() => handleSignIn('google')}
        disabled={isLoading}
      >
        {isLoading ? 'Signing in...' : 'Sign in with Google'}
      </button>
    </div>
  )
}