πŸ’‘ Key Takeaways

🧩 Server vs Client: Server components run on the server by default; client ones require 'use client'.
βš™οΈ Data Flow: Pass serializable props to server components; manage state in client ones.
πŸš€ Best Practice: Use server components whenever possible β€” they’re faster and lighter.

🧠 Server Components

  • Default rendering mode in the App Router
  • Can use async/await and fetch directly
  • Great for data fetching and SSR
// app/components/ServerComponent.js
export default async function ServerComponent() {
  const res = await fetch('https://api.example.com/posts');
  const posts = await res.json();

  return (
    <ul>
      {posts.map(p => <li key={p.id}>{p.title}</li>)}
    </ul>
  );
}

⚑ Client Components

  • Must start with 'use client' at the top
  • Can use React hooks like useState and useEffect
  • Runs only in the browser, not on the server
'use client';
import { useState, useEffect } from 'react';

export default function ClientComponent() {
  const [count, setCount] = useState(0);
  useEffect(() => console.log('Mounted!'), []);

  return <button onClick={() => setCount(c => c + 1)}>Count: {count}</button>;
}

🧱 Component Boundaries

  • Server components can wrap client components
  • Client components cannot import server ones
  • Mix them strategically for performance
import ServerComp from './ServerComponent';
import ClientComp from './ClientComponent';

export default function Page() {
  return (
    <>
      <ServerComp />
      <ClientComp />
      <ServerComp><ClientComp /></ServerComp>
    </>
  );
}

πŸ—οΈ Layout Components

  • Use to define app-wide structure
  • Combine headers, footers, and main content
  • Wrap with a root layout for consistency
export default function Layout({ children }) {
  return (
    <div className="min-h-screen flex flex-col">
      <header>Header</header>
      <main className="flex-1">{children}</main>
      <footer>Footer</footer>
    </div>
  );
}

πŸ“¦ Container Components

  • Reusable wrapper for layout consistency
  • Keeps content centered and responsive
  • Accepts children and optional class names
export default function Container({ children, className = '' }) {
  return <div className={`max-w-6xl mx-auto px-4 ${className}`}>{children}</div>;
}

πŸ”’ Higher-Order Components

  • Wrap logic around base components
  • Useful for authentication or role gating
  • Return enhanced versions of components
'use client';
import { useSession } from 'next-auth/react';

export const withAuth = (Comp) => (props) => {
  const { data: session } = useSession();
  if (!session) return <p>Access denied</p>;
  return <Comp {...props} session={session} />;
};

πŸ” Props & Data Flow

  • Pass serializable props to server components
  • Client components can accept functions and hooks
  • Combine props and children for flexible UI
export default function UserCard({ user, showEmail }) {
  return (
    <div>
      <h3>{user.name}</h3>
      {showEmail && <p>{user.email}</p>}
    </div>
  );
}

🧩 Rendering Strategies

  • Static = rendered at build time
  • Dynamic = rendered per request
  • Streaming = rendered progressively with Suspense
export const dynamic = 'force-dynamic';

export default async function DynamicComponent() {
  const res = await fetch('https://api.example.com/data', { cache: 'no-store' });
  const data = await res.json();
  return <pre>{JSON.stringify(data, null, 2)}</pre>;
}

βš™οΈ Performance Optimizations

  • Memoize expensive renders with React.memo()
  • Lazy-load heavy components with dynamic()
  • Use Suspense for partial hydration
import dynamic from 'next/dynamic';
const Chart = dynamic(() => import('./HeavyChart'), { ssr: false });

export default function LazyComp() {
  return <Chart />;
}

🧠 Error Handling

  • Wrap client code in an error boundary
  • Use fallback UI to recover gracefully
  • Log errors in componentDidCatch
'use client';
import { Component } from 'react';

export class ErrorBoundary extends Component {
  state = { hasError: false };
  static getDerivedStateFromError() { return { hasError: true }; }
  render() {
    return this.state.hasError ? <p>Something broke!</p> : this.props.children;
  }
}

πŸ“ Form Components

  • Use server actions for secure submissions
  • Use useFormState for inline feedback
  • Client forms handle interactivity and validation
'use client';
import { useState } from 'react';

export default function ClientForm() {
  const [form, setForm] = useState({ name: '', email: '' });
  const handleSubmit = (e) => { e.preventDefault(); alert('Submitted!'); };
  return (
    <form onSubmit={handleSubmit}>
      <input value={form.name} onChange={e => setForm({ ...form, name: e.target.value })}/>
      <input value={form.email} onChange={e => setForm({ ...form, email: e.target.value })}/>
      <button type="submit">Send</button>
    </form>
  );
}

🧭 Best Practices

  • Keep components small and focused
  • Use server components by default
  • Add 'use client' only when necessary
// βœ… Good pattern
app/
β”œβ”€β”€ components/
β”‚   β”œβ”€β”€ ui/       # Shared UI
β”‚   β”œβ”€β”€ layout/   # Page structure
β”‚   └── forms/    # Form logic

Disclaimer: The information provided on this website is for educational and informational purposes only. Health-related content is not intended to serve as medical advice, diagnosis, or treatment recommendations and should not replace consultation with qualified healthcare professionals. Financial content is for educational purposes only and does not constitute financial advice, investment recommendations, or professional financial planning services. Always consult with licensed healthcare providers for medical concerns and qualified financial advisors for personalized financial guidance.