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)

results matching ""

    No results matching ""