Next.js - React Framework
Overview
Next.js is our primary framework for building React applications. It provides a robust foundation with built-in optimizations, routing, and server-side rendering capabilities.
Why Next.js?
- โก Performance: Automatic optimizations and code splitting
- ๐ Rendering Options: SSR, SSG, ISR, and CSR
- ๐ File-based Routing: Intuitive routing system
- ๐ผ๏ธ Image Optimization: Built-in next/image component
- ๐ฆ API Routes: Full-stack capabilities
- ๐ง Developer Experience: Fast refresh, TypeScript support
Use Cases at Tresor
Applications Built with Next.js
- PVPipe Frontend
- E-commerce Storefronts
- Admin Dashboards
- Marketing Websites
- Documentation Sites
Rendering Strategies
- SSG: Marketing pages, documentation
- SSR: Dynamic content, user dashboards
- ISR: Product pages, blog posts
- CSR: Interactive features, real-time data
Getting Started
Project Setup
# Create new Next.js app
npx create-next-app@latest my-app --typescript --tailwind --app
# Our custom template
npx create-next-app@latest my-app --example https://github.com/tresor/nextjs-template
Project Structure
nextjs-app/
โโโ app/ # App router (Next.js 13+)
โ โโโ layout.tsx # Root layout
โ โโโ page.tsx # Home page
โ โโโ api/ # API routes
โโโ components/ # React components
โโโ lib/ # Utility functions
โโโ hooks/ # Custom hooks
โโโ styles/ # Global styles
โโโ public/ # Static assets
Key Concepts
App Router (Next.js 13+)
// app/layout.tsx
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
// app/page.tsx
export default function HomePage() {
return <h1>Welcome to Tresor</h1>
}
Data Fetching
// Server Component (default)
async function ProductList() {
const products = await fetch('https://api.example.com/products')
return <div>{/* Render products */}</div>
}
// Client Component
'use client'
import { useState, useEffect } from 'react'
function InteractiveComponent() {
const [data, setData] = useState(null)
// Client-side logic
}
API Routes
// app/api/products/route.ts
import { NextResponse } from 'next/server'
export async function GET() {
const products = await getProducts()
return NextResponse.json(products)
}
export async function POST(request: Request) {
const body = await request.json()
const product = await createProduct(body)
return NextResponse.json(product)
}
Best Practices
Performance Optimization
- Use next/image for images
- Implement proper caching strategies
- Lazy load components
- Optimize bundle size
- Use static generation when possible
SEO Optimization
// app/layout.tsx
export const metadata = {
title: 'Tresor - Your Page Title',
description: 'Page description',
openGraph: {
title: 'Tresor',
description: 'Description',
url: 'https://tresor.vn',
images: ['/og-image.jpg'],
},
}
Code Organization
components/
โโโ ui/ # Generic UI components
โโโ features/ # Feature-specific components
โโโ layouts/ # Layout components
โโโ providers/ # Context providers
State Management
- Server state: React Query/SWR
- Client state: Zustand/Redux Toolkit
- Form state: React Hook Form
- Global state: Context API
Common Patterns
Authentication
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const token = request.cookies.get('token')
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url))
}
}
Error Handling
// app/error.tsx
'use client'
export default function Error({
error,
reset,
}: {
error: Error
reset: () => void
}) {
return (
<div>
<h2>Something went wrong!</h2>
<button onClick={() => reset()}>Try again</button>
</div>
)
}
Loading States
// app/loading.tsx
export default function Loading() {
return <div>Loading...</div>
}
Deployment
Vercel Deployment
- Automatic deployments from Git
- Preview deployments for PRs
- Edge functions support
Self-Hosted
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:18-alpine AS runner
WORKDIR /app
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public
COPY --from=builder /app/package*.json ./
RUN npm ci --only=production
EXPOSE 3000
CMD ["npm", "start"]
Testing
Unit Testing
// __tests__/component.test.tsx
import { render, screen } from '@testing-library/react'
import Component from '@/components/Component'
describe('Component', () => {
it('renders correctly', () => {
render(<Component />)
expect(screen.getByText('Expected text')).toBeInTheDocument()
})
})
E2E Testing
// e2e/app.test.ts
import { test, expect } from '@playwright/test'
test('homepage loads correctly', async ({ page }) => {
await page.goto('/')
await expect(page).toHaveTitle(/Tresor/)
})
Troubleshooting
Common Issues
- Hydration mismatches
- Build errors
- Performance problems
- Deployment issues
Performance Debugging
- Use React DevTools Profiler
- Analyze bundle with @next/bundle-analyzer
- Monitor Core Web Vitals
- Check server response times
Resources
Team Support
For Next.js questions:
- Frontend Team Lead
- Senior React Developers
- DevOps (for deployment)