Menu

React & Next.js Topic

React & Next.js Introduction

React Introduction

What is React?

React is a JavaScript library for building user interfaces, particularly web applications. Developed by Facebook, it's:

  • Component-based - Build encapsulated components

  • Declarative - Describe what the UI should look like

  • Learn once, write anywhere - Works with different renderers

Why React?

  • Virtual DOM - Efficient updates

  • Component Reusability - Write once, use everywhere

  • Large Ecosystem - Vast community and libraries

  • Performance - Optimized rendering

  • Developer Experience - Great tools and debugging

React Fundamentals

1. JSX (JavaScript XML)

jsx

// JSX allows HTML-like syntax in JavaScript
const element = <h1>Hello, World!</h1>;

// Embedding expressions
const name = 'John';
const greeting = <h1>Hello, {name}!</h1>;

// JSX attributes
const image = <img src="profile.jpg" alt="Profile" className="photo" />;

// JSX is closer to JavaScript than HTML
// className instead of class, htmlFor instead of for

2. Components

Functional Components (Modern)

jsx

// Simple functional component
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

// Arrow function component
const Welcome = (props) => {
  return <h1>Hello, {props.name}</h1>;
};

// Implicit return
const Welcome = (props) => <h1>Hello, {props.name}</h1>;

Class Components (Legacy)

jsx

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

3. Props (Properties)

jsx

// Passing props to components
function UserProfile(props) {
  return (
    <div>
      <h2>{props.name}</h2>
      <p>Age: {props.age}</p>
      <p>Email: {props.email}</p>
    </div>
  );
}

// Using the component
<UserProfile name="John Doe" age={30} email="john@example.com" />

// Destructuring props (recommended)
function UserProfile({ name, age, email }) {
  return (
    <div>
      <h2>{name}</h2>
      <p>Age: {age}</p>
      <p>Email: {email}</p>
    </div>
  );
}

4. State with useState Hook

jsx

import { useState } from 'react';

function Counter() {
  // useState returns [currentValue, setterFunction]
  const [count, setCount] = useState(0);
  const [name, setName] = useState('');

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
      
      <input 
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="Enter your name"
      />
      <p>Hello, {name}!</p>
    </div>
  );
}

5. Event Handling

jsx

function ButtonComponent() {
  const handleClick = (event) => {
    console.log('Button clicked!', event);
  };

  const handleSubmit = (event) => {
    event.preventDefault();
    console.log('Form submitted!');
  };

  return (
    <div>
      <button onClick={handleClick}>Click me</button>
      
      <form onSubmit={handleSubmit}>
        <input type="text" />
        <button type="submit">Submit</button>
      </form>
    </div>
  );
}

6. Conditional Rendering

jsx

function Greeting({ isLoggedIn, user }) {
  return (
    <div>
      {isLoggedIn ? (
        <h1>Welcome back, {user.name}!</h1>
      ) : (
        <h1>Please log in.</h1>
      )}
      
      {/* Short-circuit evaluation */}
      {isLoggedIn && <p>You have 5 new messages.</p>}
      
      {/* Multiple conditions */}
      {user.role === 'admin' && <button>Admin Panel</button>}
    </div>
  );
}

7. Lists and Keys

jsx

function TodoList() {
  const [todos, setTodos] = useState([
    { id: 1, text: 'Learn React', completed: false },
    { id: 2, text: 'Build a project', completed: true },
    { id: 3, text: 'Deploy application', completed: false }
  ]);

  return (
    <ul>
      {todos.map(todo => (
        <li key={todo.id}>
          <span style={{
            textDecoration: todo.completed ? 'line-through' : 'none'
          }}>
            {todo.text}
          </span>
        </li>
      ))}
    </ul>
  );
}

8. useEffect Hook

jsx

import { useState, useEffect } from 'react';

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  // Effect runs after every render
  useEffect(() => {
    // Fetch user data
    fetch(`/api/users/${userId}`)
      .then(response => response.json())
      .then(userData => {
        setUser(userData);
        setLoading(false);
      });
  }, [userId]); // Only re-run if userId changes

  // Cleanup effect
  useEffect(() => {
    const timer = setInterval(() => {
      console.log('Timer tick');
    }, 1000);

    return () => clearInterval(timer); // Cleanup on unmount
  }, []); // Empty dependency array = run once on mount

  if (loading) return <div>Loading...</div>;

  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  );
}

Next.js Introduction

What is Next.js?

Next.js is a React framework that provides:

  • Server-side rendering (SSR)

  • Static site generation (SSG)

  • API routes - Backend functionality

  • File-based routing

  • Built-in CSS support

  • Optimized performance

Why Next.js?

  • Better SEO - Server-side rendering

  • Improved Performance - Automatic code splitting

  • Full-stack Capabilities - API routes

  • Zero Configuration - Built-in optimizations

  • Production Ready - Many features out-of-the-box

Next.js Fundamentals

1. Project Structure

text

my-next-app/
├── pages/                 # File-based routing
│   ├── index.js          # / route
│   ├── about.js          # /about route
│   ├── blog/
│   │   └── [slug].js     # Dynamic route /blog/anything
│   └── api/              # API routes
│       └── users.js      # /api/users endpoint
├── public/               # Static assets
├── styles/               # CSS files
├── components/           # Reusable components
└── package.json

2. Pages and Routing

jsx

// pages/index.js
export default function Home() {
  return <h1>Welcome to the Home Page!</h1>;
}

// pages/about.js
export default function About() {
  return <h1>About Us</h1>;
}

// pages/blog/[slug].js - Dynamic route
import { useRouter } from 'next/router';

export default function BlogPost() {
  const router = useRouter();
  const { slug } = router.query;

  return (
    <div>
      <h1>Blog Post: {slug}</h1>
      <p>This is the blog post content for {slug}.</p>
    </div>
  );
}

3. Navigation with Link

jsx

import Link from 'next/link';

function Navigation() {
  return (
    <nav>
      <Link href="/">
        <a>Home</a>
      </Link>
      <Link href="/about">
        <a>About</a>
      </Link>
      <Link href="/blog/first-post">
        <a>First Post</a>
      </Link>
      
      {/* Programmatic navigation */}
      <button onClick={() => router.push('/contact')}>
        Go to Contact
      </button>
    </nav>
  );
}

4. Data Fetching Methods

getStaticProps (Static Generation)

jsx

// pages/blog/index.js
export default function Blog({ posts }) {
  return (
    <div>
      <h1>Blog Posts</h1>
      {posts.map(post => (
        <article key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.excerpt}</p>
        </article>
      ))}
    </div>
  );
}

// This runs at build time
export async function getStaticProps() {
  const posts = await fetch('https://api.example.com/posts').then(res => res.json());

  return {
    props: {
      posts
    },
    revalidate: 60 // Re-generate every 60 seconds (ISR)
  };
}

getServerSideProps (Server-Side Rendering)

jsx

// pages/user/[id].js
export default function User({ user }) {
  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  );
}

// This runs on every request
export async function getServerSideProps(context) {
  const { id } = context.params;
  
  const user = await fetch(`https://api.example.com/users/${id}`)
    .then(res => res.json());

  return {
    props: {
      user
    }
  };
}

getStaticPaths (Dynamic Static Pages)

jsx

// pages/blog/[slug].js
export default function BlogPost({ post }) {
  return (
    <article>
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />
    </article>
  );
}

// Define which paths to pre-render
export async function getStaticPaths() {
  const posts = await fetch('https://api.example.com/posts').then(res => res.json());

  const paths = posts.map(post => ({
    params: { slug: post.slug }
  }));

  return {
    paths,
    fallback: false // Show 404 for non-pre-rendered paths
  };
}

export async function getStaticProps({ params }) {
  const post = await fetch(`https://api.example.com/posts/${params.slug}`)
    .then(res => res.json());

  return {
    props: {
      post
    }
  };
}

5. API Routes

jsx

// pages/api/users.js
export default function handler(req, res) {
  const { method } = req;

  switch (method) {
    case 'GET':
      // Get users from database
      res.status(200).json([
        { id: 1, name: 'John Doe' },
        { id: 2, name: 'Jane Smith' }
      ]);
      break;
    
    case 'POST':
      // Create new user
      const { name, email } = req.body;
      // Save to database...
      res.status(201).json({ id: 3, name, email });
      break;
    
    default:
      res.setHeader('Allow', ['GET', 'POST']);
      res.status(405).end(`Method ${method} Not Allowed`);
  }
}

// Using the API route in components
async function fetchUsers() {
  const response = await fetch('/api/users');
  const users = await response.json();
  return users;
}

6. Styling in Next.js

CSS Modules

jsx

// components/Button.module.css
.button {
  padding: 10px 20px;
  background: blue;
  color: white;
  border: none;
  border-radius: 4px;
}

.primary {
  background: darkblue;
}

// Using CSS Modules
import styles from './Button.module.css';

export default function Button({ children, primary }) {
  return (
    <button className={`${styles.button} ${primary ? styles.primary : ''}`}>
      {children}
    </button>
  );
}

Styled JSX

jsx

function Header() {
  return (
    <header>
      <h1>My Website</h1>
      <style jsx>{`
        header {
          background: #333;
          color: white;
          padding: 20px;
        }
        
        h1 {
          margin: 0;
          font-size: 2rem;
        }
      `}</style>
    </header>
  );
}

Tailwind CSS (Popular Choice)

jsx

function Card({ title, content }) {
  return (
    <div className="max-w-sm rounded overflow-hidden shadow-lg bg-white">
      <div className="px-6 py-4">
        <div className="font-bold text-xl mb-2">{title}</div>
        <p className="text-gray-700 text-base">{content}</p>
      </div>
    </div>
  );
}

Advanced React Concepts

1. Custom Hooks

jsx

// hooks/useLocalStorage.js
import { useState, useEffect } from 'react';

export function useLocalStorage(key, initialValue) {
  // Get from localStorage or use initial value
  const [storedValue, setStoredValue] = useState(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      return initialValue;
    }
  });

  // Update localStorage when value changes
  const setValue = (value) => {
    try {
      setStoredValue(value);
      window.localStorage.setItem(key, JSON.stringify(value));
    } catch (error) {
      console.log(error);
    }
  };

  return [storedValue, setValue];
}

// Using the custom hook
function UserPreferences() {
  const [theme, setTheme] = useLocalStorage('theme', 'light');
  const [language, setLanguage] = useLocalStorage('language', 'en');

  return (
    <div>
      <select value={theme} onChange={(e) => setTheme(e.target.value)}>
        <option value="light">Light</option>
        <option value="dark">Dark</option>
      </select>
      
      <select value={language} onChange={(e) => setLanguage(e.target.value)}>
        <option value="en">English</option>
        <option value="es">Spanish</option>
      </select>
    </div>
  );
}

2. Context API

jsx

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

const ThemeContext = createContext();

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

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

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

// Custom hook to use theme context
export function useTheme() {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error('useTheme must be used within a ThemeProvider');
  }
  return context;
}

// Using in components
function ThemeToggle() {
  const { theme, toggleTheme } = useTheme();

  return (
    <button onClick={toggleTheme}>
      Switch to {theme === 'light' ? 'dark' : 'light'} mode
    </button>
  );
}

// Wrap app with provider
function App() {
  return (
    <ThemeProvider>
      <ThemeToggle />
      {/* Rest of app */}
    </ThemeProvider>
  );
}

3. Higher-Order Components (HOCs)

jsx

// HOC for authentication
function withAuth(WrappedComponent) {
  return function AuthenticatedComponent(props) {
    const [isAuthenticated, setIsAuthenticated] = useState(false);
    const [loading, setLoading] = useState(true);

    useEffect(() => {
      // Check authentication
      checkAuth().then(auth => {
        setIsAuthenticated(auth);
        setLoading(false);
      });
    }, []);

    if (loading) return <div>Loading...</div>;
    
    if (!isAuthenticated) {
      return <div>Please log in to view this content.</div>;
    }

    return <WrappedComponent {...props} />;
  };
}

// Using HOC
const ProtectedProfile = withAuth(UserProfile);

Next.js Advanced Features

1. Image Optimization

jsx

import Image from 'next/image';

function OptimizedImage() {
  return (
    <div>
      <Image
        src="/profile.jpg"
        alt="Profile picture"
        width={500}
        height={300}
        placeholder="blur"
        blurDataURL="data:image/jpeg;base64,..."
        priority // Load above the fold images first
      />
    </div>
  );
}
2. Dynamic Imports
jsx

import dynamic from 'next/dynamic';

// Lazy load heavy components
const HeavyComponent = dynamic(() => import('../components/HeavyComponent'), {
  loading: () => <p>Loading...</p>,
  ssr: false // Disable server-side rendering for this component
});

function HomePage() {
  return (
    <div>
      <h1>Home Page</h1>
      <HeavyComponent />
    </div>
  );
}

3. Environment Variables

jsx

// .env.local
API_URL=https://api.example.com
SECRET_KEY=your-secret-key

// Using environment variables
export async function getServerSideProps() {
  const apiUrl = process.env.API_URL;
  
  const data = await fetch(`${apiUrl}/posts`).then(res => res.json());

  return {
    props: {
      posts: data
    }
  };
}

Complete Example: Blog Application

Project Structure

text

blog-app/
├── components/
│   ├── Layout.js
│   ├── Header.js
│   ├── PostCard.js
│   └── SEO.js
├── pages/
│   ├── index.js
│   ├── about.js
│   ├── blog/
│   │   ├── index.js
│   │   └── [slug].js
│   └── api/
│       └── posts.js
├── styles/
│   └── globals.css
└── lib/
    └── api.js

Key Components

jsx

// components/Layout.js
import Head from 'next/head';
import Header from './Header';

export default function Layout({ children, title = 'My Blog' }) {
  return (
    <>
      <Head>
        <title>{title}</title>
        <meta name="description" content="A modern blog built with Next.js" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      
      <Header />
      <main className="container">
        {children}
      </main>
    </>
  );
}

// pages/index.js
import Layout from '../components/Layout';
import PostCard from '../components/PostCard';

export default function Home({ featuredPosts }) {
  return (
    <Layout title="Home - My Blog">
      <section className="hero">
        <h1>Welcome to My Blog</h1>
        <p>Discover amazing articles about web development</p>
      </section>
      
      <section className="featured-posts">
        <h2>Featured Posts</h2>
        <div className="posts-grid">
          {featuredPosts.map(post => (
            <PostCard key={post.id} post={post} />
          ))}
        </div>
      </section>
    </Layout>
  );
}

export async function getStaticProps() {
  const featuredPosts = await fetch('https://api.example.com/posts/featured')
    .then(res => res.json());

  return {
    props: {
      featuredPosts
    },
    revalidate: 3600 // Re-generate every hour
  };
}

Learning Path Recommendations

Beginner Level (1-2 weeks)

  1. React Fundamentals: Components, JSX, Props, State

  2. Basic Hooks: useState, useEffect

  3. Event Handling and Conditional Rendering

  4. Simple Next.js Setup and Pages

Intermediate Level (2-4 weeks)

  1. Advanced Hooks: useContext, useReducer, custom hooks

  2. Context API for state management

  3. Next.js Data Fetching: getStaticProps, getServerSideProps

  4. API Routes and Dynamic Routing

  5. Styling Approaches: CSS Modules, Tailwind

Advanced Level (4+ weeks)

  1. Performance Optimization: memo, useMemo, useCallback

  2. Testing: Jest, React Testing Library

  3. Authentication and Authorization

  4. Deployment and CI/CD

  5. Advanced Next.js: Middleware, Incremental Static Regeneration

Key Takeaways

  • React is the library for building UI components

  • Next.js is the framework that provides structure and features

  • Components are the building blocks of React applications

  • Hooks manage state and side effects in functional components

  • Next.js offers multiple rendering strategies for different use cases

  • File-based routing makes navigation intuitive

  • API routes enable full-stack development in a single framework

This foundation will help you build modern, performant web applications with React and Next.js!

Comments (0)

No comments yet. Be the first to comment!

LecturreAI Assistant

Hello! I'm LecturreAI

What would you like to learn today?