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)
-
React Fundamentals: Components, JSX, Props, State
-
Basic Hooks: useState, useEffect
-
Event Handling and Conditional Rendering
-
Simple Next.js Setup and Pages
Intermediate Level (2-4 weeks)
-
Advanced Hooks: useContext, useReducer, custom hooks
-
Context API for state management
-
Next.js Data Fetching: getStaticProps, getServerSideProps
-
API Routes and Dynamic Routing
-
Styling Approaches: CSS Modules, Tailwind
Advanced Level (4+ weeks)
-
Performance Optimization: memo, useMemo, useCallback
-
Testing: Jest, React Testing Library
-
Authentication and Authorization
-
Deployment and CI/CD
-
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!