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
- 1Server sends initial HTML
Basic structure without interactivity
- 2Browser downloads JavaScript
React bundle loads in the browser
- 3React hydrates the page
Attaches event handlers and state
- 4Component becomes interactive
Users can click, type, and interact
- 5Updates 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>
)
}