Next.js course Β· Module 1: Next.js Configuration

Directory and File Structure in Next.js (app/ vs pages/)

12 min read
In this lesson9

In Quantum Metropolis, engineers design advanced transportation systems that can operate both on classic roads and on new quantum teleportation routes. Similarly, Next.js offers two parallel routing systems: the traditional Pages Router and the modern App Router. In this module, we will thoroughly analyze the differences between these two approaches and understand how to organize files and directories in our projects.

Two Routing Philosophies in Next.js

Next.js originally relied on file-based routing in the pages/ folder. In Next.js 13, a new routing system based on the app/ folder was introduced. This evolution resembles the transition from classic transportation systems to quantum teleportation in Quantum Metropolis - the new technology is more advanced, but both still coexist.

Pages Router: The Classic Approach

The Pages Router is the original routing system in Next.js. It is simple, well-documented, and still widely used. In this convention, every JavaScript or TypeScript file in the pages/ directory automatically becomes a route in the application.

1pages/
2β”œβ”€β”€ index.js                # Route: /
3β”œβ”€β”€ about.js                # Route: /about
4β”œβ”€β”€ contact.tsx             # Route: /contact
5β”œβ”€β”€ products/
6β”‚   β”œβ”€β”€ index.js            # Route: /products
7β”‚   └── [id].js             # Route: /products/:id (dynamic)
8└── api/
9    └── hello.js            # API Endpoint: /api/hello

In this system:

  • Files directly map to URL paths
  • Dynamic path segments are marked with square brackets [param]
  • A special api/ directory is used for handling API endpoints
  • Each file exports a React component or API handler function by default

App Router: The Modern Approach

The App Router, introduced in Next.js 13 and refined in version 15, represents a new approach based on React Server Components. It is like transitioning from traditional vehicles to quantum teleportation - a fundamental change in how we think about web applications.

1app/
2β”œβ”€β”€ layout.tsx              # Main layout (required)
3β”œβ”€β”€ page.tsx                # Route: /
4β”œβ”€β”€ about/
5β”‚   └── page.tsx            # Route: /about
6β”œβ”€β”€ blog/
7β”‚   β”œβ”€β”€ page.tsx            # Route: /blog
8β”‚   β”œβ”€β”€ layout.tsx          # Layout specific to /blog and its sub-routes
9β”‚   └── [slug]/
10β”‚       └── page.tsx        # Route: /blog/:slug (dynamic)
11└── api/
12    └── users/
13        └── route.ts        # API Endpoint: /api/users

In the App Router:

  • Only directories define routes, and special files within those directories serve specific functions
  • The page.tsx file renders the page component for a given route
  • The layout.tsx file defines a shared layout for all pages in the directory and its subdirectories
  • Dynamic segments still use square brackets: [param]
  • API endpoints are created using route.ts files

File Naming and Conventions in App Router

The App Router introduces "convention over configuration" with a series of special files that have specific roles. This is like specialized modules in Quantum Metropolis systems - each with a defined function in the overall architecture.

Basic Special Files:

  1. page.tsx: Renders the route's user interface and makes the path publicly accessible.

    1// app/dashboard/page.tsx
    2export default function DashboardPage() {
    3  return (
    4    <section>
    5      <h1>Quantum Metropolis Control Panel</h1>
    6      <p>Welcome to the command center!</p>
    7    </section>
    8  );
    9}
  2. layout.tsx: Defines a shared interface for a segment and its children.

    1// app/dashboard/layout.tsx
    2export default function DashboardLayout({
    3  children,
    4}: {
    5  children: React.ReactNode;
    6}) {
    7  return (
    8    <div className="dashboard-layout">
    9      <nav className="dashboard-sidebar">
    10        {/* Sidebar navigation */}
    11      </nav>
    12      <main className="dashboard-main">{children}</main>
    13    </div>
    14  );
    15}
  3. route.ts: Creates an API endpoint using the new request handling API.

    1// app/api/status/route.ts
    2import { NextResponse } from 'next/server';
    3
    4export async function GET() {
    5  return NextResponse.json({
    6    status: 'online',
    7    systemsOperational: 15,
    8    time: new Date().toISOString()
    9  });
    10}
    11
    12export async function POST(request: Request) {
    13  const data = await request.json();
    14  // Processing data...
    15  return NextResponse.json({ success: true });
    16}
  4. loading.tsx: Creates a loading interface with React Suspense.

    1// app/dashboard/loading.tsx
    2export default function DashboardLoading() {
    3  return (
    4    <div className="dashboard-loading">
    5      <div className="spinner"></div>
    6      <p>Loading Metropolis system data...</p>
    7    </div>
    8  );
    9}
  5. error.tsx: Creates an error handling interface with React Error Boundary.

    1'use client'; // Error handling components must be client components
    2
    3import { useEffect } from 'react';
    4
    5export default function DashboardError({
    6  error,
    7  reset,
    8}: {
    9  error: Error;
    10  reset: () => void;
    11}) {
    12  useEffect(() => {
    13    // Log error to monitoring system
    14    console.error(error);
    15  }, [error]);
    16
    17  return (
    18    <div className="error-container">
    19      <h2>An error occurred in the Metropolis systems!</h2>
    20      <p>{error.message}</p>
    21      <button onClick={reset}>Try again</button>
    22    </div>
    23  );
    24}
  6. not-found.tsx: Creates an interface for a not-found resource (404).

    1// app/not-found.tsx
    2export default function NotFound() {
    3  return (
    4    <div className="not-found">
    5      <h2>Unknown Zone</h2>
    6      <p>No Quantum Metropolis module was found with that identifier.</p>
    7      <a href="/">Return to command center</a>
    8    </div>
    9  );
    10}

Advanced App Router Features

The App Router introduces several advanced organizational features that resemble the advanced transportation systems in Quantum Metropolis - they allow for more complex and flexible routes.

1. Route Groups

Route groups allow organizing files without affecting the URL structure. They are marked by enclosing the directory name in parentheses: (group-name).

1app/
2β”œβ”€β”€ (marketing)/        # Route group (does not affect URL path)
3β”‚   β”œβ”€β”€ about/
4β”‚   β”‚   └── page.tsx    # Route: /about
5β”‚   └── contact/
6β”‚       └── page.tsx    # Route: /contact
7└── (dashboard)/        # Another route group
8    β”œβ”€β”€ layout.tsx      # Shared layout for dashboard routes
9    β”œβ”€β”€ page.tsx        # Route: /
10    └── stats/
11        └── page.tsx    # Route: /stats

Route groups are like districts in Quantum Metropolis - they help organize the city structure, but don't affect addresses.

2. Parallel Routes

Parallel routes allow simultaneous rendering of multiple pages in the same view, which is useful for complex layouts. They are marked by a slot name with the "@" sign: @slot-name.

1app/
2β”œβ”€β”€ layout.tsx          # Main layout
3β”œβ”€β”€ page.tsx            # Main page
4└── dashboard/
5    β”œβ”€β”€ layout.tsx      # Layout with multiple slots
6    β”‚   // layout.tsx defines slots {children, @stats, @notifications}
7    β”œβ”€β”€ page.tsx        # Default content for the main slot
8    β”œβ”€β”€ @stats/
9    β”‚   β”œβ”€β”€ page.tsx    # Content for the @stats slot
10    β”‚   └── default.tsx # Required in Next.js 16 (e.g. returns null)
11    └── @notifications/
12        β”œβ”€β”€ page.tsx    # Content for the @notifications slot
13        └── default.tsx # Required in Next.js 16 (e.g. returns null)

In Next.js 16 every slot needs a default.tsx file (for example one that returns null or calls notFound()), otherwise next build fails.

1// app/dashboard/layout.tsx
2export default function DashboardLayout({
3  children,
4  stats,
5  notifications,
6}: {
7  children: React.ReactNode;
8  stats: React.ReactNode;
9  notifications: React.ReactNode;
10}) {
11  return (
12    <div className="dashboard-grid">
13      <main>{children}</main>
14      <aside className="stats-panel">{stats}</aside>
15      <section className="notifications-panel">{notifications}</section>
16    </div>
17  );
18}

Parallel routes are like parallel dimensions in Quantum Metropolis - different realities accessible simultaneously.

3. Intercepting Routes

These allow "intercepting" a route and displaying it differently, which is ideal for modals that preserve navigation context. They are marked by the segment name with the sign "(.)": (.)name, (..)name or (...)name.

1app/
2β”œβ”€β”€ layout.tsx
3β”œβ”€β”€ page.tsx            # Route: /
4└── dashboard/
5    β”œβ”€β”€ layout.tsx
6    β”œβ”€β”€ page.tsx        # Route: /dashboard
7    └── projects/
8        β”œβ”€β”€ layout.tsx       # Renders {children} and {modal}
9        β”œβ”€β”€ page.tsx         # Route: /dashboard/projects
10        β”œβ”€β”€ [id]/
11        β”‚   └── page.tsx     # Route: /dashboard/projects/:id
12        β”œβ”€β”€ create/
13        β”‚   └── page.tsx     # Route: /dashboard/projects/create (full page)
14        └── @modal/
15            β”œβ”€β”€ default.tsx  # Returns null when the modal is closed
16            └── (.)create/
17                └── page.tsx # Modal over the list when opened via a link

When you follow a link from the list, Next.js shows the intercepted page in the @modal slot over the list; after a refresh or when you open the address directly, it shows the full create/page.tsx page.

Intercepting routes are like quantum shortcuts in Quantum Metropolis - they allow quick access to resources without changing context.

Code Organization in Next.js 16

Besides the routing structure, Next.js 16 suggests specific ways of organizing code. This is like planning districts in Quantum Metropolis - proper organization increases efficiency and readability.

Shared Components and Resources

Components used in multiple places should be organized consistently. Here is the recommended structure:

1src/
2β”œβ”€β”€ app/                 # Application with App Router
3β”‚   β”œβ”€β”€ layout.tsx
4β”‚   └── page.tsx
5β”œβ”€β”€ components/          # Shared components
6β”‚   β”œβ”€β”€ ui/              # Basic UI components
7β”‚   β”‚   β”œβ”€β”€ Button.tsx
8β”‚   β”‚   └── Card.tsx
9β”‚   └── features/        # Feature-specific components
10β”‚       β”œβ”€β”€ dashboard/
11β”‚       └── auth/
12β”œβ”€β”€ lib/                 # Shared functions and classes
13β”‚   β”œβ”€β”€ api/
14β”‚   └── utils/
15β”œβ”€β”€ hooks/               # Custom React hooks
16β”‚   β”œβ”€β”€ useAuth.ts
17β”‚   └── useLocalStorage.ts
18└── styles/              # Global styles
19    └── globals.css

Co-location vs. Centralization

Next.js 16 and the App Router support a "co-location" approach, where files related to a specific route are placed close together. This is like micro-districts in Quantum Metropolis - everything you need is nearby.

1app/
2└── dashboard/
3    β”œβ”€β”€ page.tsx
4    β”œβ”€β”€ loading.tsx       # Loading for this route
5    β”œβ”€β”€ error.tsx         # Error handling for this route
6    β”œβ”€β”€ layout.tsx        # Layout for this route
7    β”œβ”€β”€ actions.ts        # Server Actions for this route
8    β”œβ”€β”€ components/       # Components specific to this route
9    β”‚   β”œβ”€β”€ StatusCard.tsx
10    β”‚   └── DashboardNav.tsx
11    └── styles/           # Styles specific to this route
12        └── dashboard.module.css

Comparing App Router and Pages Router

Now that we've explored both routing systems, let's compare them - just as Quantum Metropolis engineers might compare classic transport with quantum teleportation.

Rendering

  1. Pages Router:

    • Every page is pre-rendered to HTML by default (automatic static optimization), then hydrated in the browser
    • SSR and SSG available through getServerSideProps and getStaticProps
    • Relatively simple data models
  2. App Router:

    • Server Components by default
    • Choice between Server and Client Components
    • More advanced data flow model
    • Streaming rendering

In the Pages Router, a page gets its data from a function exported next to the component, e.g. getStaticProps, which Next.js calls once, during the build:

1// pages/posts.js (Pages Router)
2export async function getStaticProps() {
3  const posts = await getPosts();
4  return { props: { posts } };
5}

The getServerSideProps function has the same shape, but Next.js calls it on every request.

Loading State

  1. Pages Router:

    • Manual loading state management
    • Often uses external libraries
  2. App Router:

    • Built-in loading.tsx components
    • Integration with React Suspense
    • Automatic loading indicators

Error Handling

  1. Pages Router:

    • Manual error management
    • General component for 500 errors
  2. App Router:

    • error.tsx components with granular error handling
    • Integration with React Error Boundary
    • Ability to recover/retry after an error

Layouts

  1. Pages Router:

    • Manual layout creation with _app.js component
    • One layout for the entire application
    • Nested layouts require additional work
  2. App Router:

    • Built-in layout system through layout.tsx
    • Ability to create nested layouts
    • Layout sharing is simple and intuitive

When to Use Which Routing System?

Choosing between App Router and Pages Router resembles choosing between quantum teleportation and traditional transport in Quantum Metropolis - it depends on specific needs.

Use App Router when:

  • You are creating a new project from scratch
  • You want to use the latest React and Next.js features
  • You need advanced layout and organization capabilities
  • You care about better performance and streaming rendering
  • You want to use React Server Components

Use Pages Router when:

  • You have an existing project based on Pages Router
  • You need a simpler mental model
  • You use libraries that are not yet compatible with the App Router
  • You want to use ready-made patterns and solutions

Migration from Pages Router to App Router

If you have an existing project using Pages Router, you can gradually migrate to App Router. This is like modernizing districts in Quantum Metropolis - you don't have to rebuild everything at once.

Next.js 16 allows both systems to coexist. You can start using app/ for new features while keeping existing pages in pages/.

1.
2β”œβ”€β”€ app/                # New features using App Router
3β”‚   β”œβ”€β”€ new-feature/
4β”‚   β”‚   └── page.tsx    # /new-feature
5β”‚   └── layout.tsx
6└── pages/              # Existing pages using Pages Router
7    β”œβ”€β”€ index.js        # /
8    └── about.js        # /about

Important notes about migration:

  • Routes in app/ take priority over routes in pages/, but the same URL cannot exist in both directories: Next.js reports an error during the build
  • Both structures use the same Next.js configuration
  • You can gradually move pages from pages/ to app/

Best Practices for File Organization

Regardless of the chosen routing system, it's worth following certain best practices:

  1. Feature-oriented structure: Organize components and code around business features, not by technical types.

    1src/
    2β”œβ”€β”€ features/
    3β”‚   β”œβ”€β”€ auth/
    4β”‚   β”‚   β”œβ”€β”€ components/
    5β”‚   β”‚   β”œβ”€β”€ hooks/
    6β”‚   β”‚   └── utils/
    7β”‚   └── dashboard/
    8β”‚       β”œβ”€β”€ components/
    9β”‚       β”œβ”€β”€ hooks/
    10β”‚       └── utils/
  2. Modular approach: Treat each feature as an isolated module with a clearly defined API.

  3. Consistent naming conventions: Establish conventions and stick to them throughout the project.

    • Component files: PascalCase (Button.tsx)
    • Hooks: camelCase with "use" prefix (useAuth.ts)
    • Helper functions: camelCase (formatDate.ts)
  4. Relative vs. absolute imports: Use import aliases (@/) for better readability and easier file moving.

  5. Test co-location: Place tests close to the tested components.

    1src/
    2β”œβ”€β”€ components/
    3β”‚   β”œβ”€β”€ Button.tsx
    4β”‚   └── Button.test.tsx

Summary

The directory and file structure in Next.js 16 is like the architecture of Quantum Metropolis - with proper planning, it can be both elegant and functional. The App Router introduces a more advanced but also more flexible application organization model, while the Pages Router offers a simpler and more direct approach.

The choice between them depends on the specific needs of the project, but for new projects, it is recommended to use the App Router to take advantage of the latest features and optimizations. Remember that good project organization is the key to easy maintenance and extensibility in the future.

In the next lesson, we will dive into the Next.js 16 component system, particularly the differences between Client Components and Server Components, which are a fundamental part of the App Router.

Code for this lesson: App.tsx
1// Props and State - Metropolis Quantum
2import React, { useState } from 'react';
3
4console.log("Props and State in React");
5console.log("Data management in Quantum City\n");
6
7// ==========================================
8// 1. PROPS - Passing Data
9// ==========================================
10console.log("=== 1. PROPS - Properties ===");
11
12interface UserCardProps {
13  name: string;
14  role: string;
15  level: number;
16  avatar: string;
17}
18
19const UserCard: React.FC<UserCardProps> = ({ name, role, level, avatar }) => {
20  return (
21    <div style={{
22      background: 'rgba(255, 255, 255, 0.1)',
23      padding: '20px',
24      borderRadius: '12px',
25      border: '2px solid #64ffda',
26      display: 'flex',
27      alignItems: 'center',
28      gap: '15px',
29      marginBottom: '15px'
30    }}>
31      <div style={{ fontSize: '3rem' }}>{avatar}</div>
32      <div>
33        <h3 style={{ color: '#64ffda', margin: '0 0 5px 0' }}>{name}</h3>
34        <p style={{ margin: '5px 0', color: '#b0bec5' }}>Role: {role}</p>
35        <p style={{ margin: '5px 0', color: '#ff9800' }}>Level: {level}</p>
36      </div>
37    </div>
38  );
39};
40
41// ==========================================
42// 2. STATE - Component State
43// ==========================================
44console.log("\n=== 2. STATE - useState Hook ===");
45
46function QuantumCounter() {
47  // useState returns [value, function to change value]
48  const [energy, setEnergy] = useState<number>(50);
49  const [isCharging, setIsCharging] = useState<boolean>(false);
50
51  const charge = () => {
52    if (energy < 100) {
53      setEnergy(energy + 10);
54      setIsCharging(true);
55      setTimeout(() => setIsCharging(false), 300);
56      console.log(`Charging energy: ${energy + 10}%`);
57    }
58  };
59
60  const discharge = () => {
61    if (energy > 0) {
62      setEnergy(energy - 10);
63      console.log(`Discharging energy: ${energy - 10}%`);
64    }
65  };
66
67  const reset = () => {
68    setEnergy(50);
69    console.log("Energy reset to 50%");
70  };
71
72  const getEnergyColor = () => {
73    if (energy > 70) return '#4caf50';
74    if (energy > 30) return '#ff9800';
75    return '#f44336';
76  };
77
78  return (
79    <div style={{
80      background: 'rgba(124, 77, 255, 0.2)',
81      padding: '20px',
82      borderRadius: '12px',
83      border: '2px solid #7c4dff'
84    }}>
85      <h3 style={{ color: '#7c4dff' }}>Quantum Energy Generator</h3>
86
87      <div style={{
88        background: 'rgba(0, 0, 0, 0.5)',
89        padding: '15px',
90        borderRadius: '8px',
91        marginBottom: '15px'
92      }}>
93        <div style={{
94          fontSize: '2rem',
95          textAlign: 'center',
96          color: getEnergyColor(),
97          marginBottom: '10px'
98        }}>
99          {energy}%
100        </div>
101        <div style={{
102          width: '100%',
103          height: '20px',
104          background: 'rgba(255, 255, 255, 0.1)',
105          borderRadius: '10px',
106          overflow: 'hidden'
107        }}>
108          <div style={{
109            width: `${energy}%`,
110            height: '100%',
111            background: `linear-gradient(90deg, ${getEnergyColor()}, #64ffda)`,
112            transition: 'all 0.3s ease',
113            transform: isCharging ? 'scale(1.05)' : 'scale(1)'
114          }}></div>
115        </div>
116      </div>
117
118      <div style={{ display: 'flex', gap: '10px', justifyContent: 'center' }}>
119        <button
120          onClick={charge}
121          disabled={energy >= 100}
122          style={{
123            background: energy >= 100 ? '#555' : 'linear-gradient(45deg, #4caf50, #8bc34a)',
124            color: 'white',
125            border: 'none',
126            padding: '10px 20px',
127            borderRadius: '6px',
128            cursor: energy >= 100 ? 'not-allowed' : 'pointer',
129            fontWeight: 'bold'
130          }}
131        >
132          Charge
133        </button>
134
135        <button
136          onClick={discharge}
137          disabled={energy <= 0}
138          style={{
139            background: energy <= 0 ? '#555' : 'linear-gradient(45deg, #f44336, #e91e63)',
140            color: 'white',
141            border: 'none',
142            padding: '10px 20px',
143            borderRadius: '6px',
144            cursor: energy <= 0 ? 'not-allowed' : 'pointer',
145            fontWeight: 'bold'
146          }}
147        >
148          Discharge
149        </button>
150
151        <button
152          onClick={reset}
153          style={{
154            background: 'linear-gradient(45deg, #607d8b, #90a4ae)',
155            color: 'white',
156            border: 'none',
157            padding: '10px 20px',
158            borderRadius: '6px',
159            cursor: 'pointer',
160            fontWeight: 'bold'
161          }}
162        >
163          Reset
164        </button>
165      </div>
166    </div>
167  );
168}
169
170// ==========================================
171// 3. Props + State Together
172// ==========================================
173console.log("\n=== 3. Props + State Combined ===");
174
175interface SystemStatusProps {
176  systemName: string;
177  initialStatus: 'online' | 'offline' | 'maintenance';
178}
179
180const SystemStatus: React.FC<SystemStatusProps> = ({ systemName, initialStatus }) => {
181  const [status, setStatus] = useState(initialStatus);
182  const [uptime, setUptime] = useState(0);
183
184  const toggleStatus = () => {
185    const statuses: Array<'online' | 'offline' | 'maintenance'> = ['online', 'offline', 'maintenance'];
186    const currentIndex = statuses.indexOf(status);
187    const nextStatus = statuses[(currentIndex + 1) % statuses.length];
188    setStatus(nextStatus);
189    setUptime(0);
190    console.log(`${systemName} status changed to: ${nextStatus}`);
191  };
192
193  const getStatusColor = () => {
194    switch(status) {
195      case 'online': return '#4caf50';
196      case 'offline': return '#f44336';
197      case 'maintenance': return '#ff9800';
198    }
199  };
200
201  return (
202    <div style={{
203      background: 'rgba(255, 255, 255, 0.1)',
204      padding: '15px',
205      borderRadius: '10px',
206      border: `2px solid ${getStatusColor()}`,
207      marginBottom: '15px'
208    }}>
209      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
210        <div>
211          <h4 style={{ margin: '0 0 10px 0', color: '#64ffda' }}>{systemName}</h4>
212          <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
213            <div style={{
214              width: '12px',
215              height: '12px',
216              borderRadius: '50%',
217              background: getStatusColor(),
218              boxShadow: `0 0 10px ${getStatusColor()}`
219            }}></div>
220            <span style={{ color: getStatusColor(), textTransform: 'uppercase', fontWeight: 'bold' }}>
221              {status}
222            </span>
223          </div>
224        </div>
225        <button
226          onClick={toggleStatus}
227          style={{
228            background: 'linear-gradient(45deg, #2196f3, #21cbf3)',
229            color: 'white',
230            border: 'none',
231            padding: '8px 16px',
232            borderRadius: '6px',
233            cursor: 'pointer',
234            fontWeight: 'bold'
235          }}
236        >
237          Toggle Status
238        </button>
239      </div>
240    </div>
241  );
242};
243
244// ==========================================
245// Main App
246// ==========================================
247function App() {
248  const citizens = [
249    { name: 'Alex Quantum', role: 'Chief Architect', level: 42, avatar: '' },
250    { name: 'Nova Star', role: 'Data Scientist', level: 38, avatar: '' },
251    { name: 'Cypher Neo', role: 'Security Expert', level: 45, avatar: '' }
252  ];
253
254  return (
255    <div style={{
256      padding: '20px',
257      background: 'linear-gradient(135deg, #0f0f23 0%, #1a1a2e 100%)',
258      minHeight: '100vh',
259      color: 'white'
260    }}>
261      <h1 style={{ textAlign: 'center', color: '#64ffda' }}>Metropolis Control Panel</h1>
262
263      <div style={{ marginTop: '30px' }}>
264        <h2 style={{ color: '#7c4dff' }}>Citizens (Props Demo)</h2>
265        {citizens.map((citizen, index) => (
266          <UserCard
267            key={index}
268            name={citizen.name}
269            role={citizen.role}
270            level={citizen.level}
271            avatar={citizen.avatar}
272          />
273        ))}
274      </div>
275
276      <div style={{ marginTop: '30px' }}>
277        <h2 style={{ color: '#7c4dff' }}>Energy System (State Demo)</h2>
278        <QuantumCounter />
279      </div>
280
281      <div style={{ marginTop: '30px' }}>
282        <h2 style={{ color: '#7c4dff' }}>Systems Status (Props + State)</h2>
283        <SystemStatus systemName="Quantum Core" initialStatus="online" />
284        <SystemStatus systemName="Neural Network" initialStatus="maintenance" />
285        <SystemStatus systemName="Transport Grid" initialStatus="offline" />
286      </div>
287
288      <div style={{
289        marginTop: '30px',
290        background: 'rgba(100, 255, 218, 0.1)',
291        padding: '20px',
292        borderRadius: '10px',
293        borderLeft: '4px solid #64ffda'
294      }}>
295        <h3>Props vs State:</h3>
296        <ul style={{ lineHeight: '1.8' }}>
297          <li><strong>Props</strong>: Passed from parent, read-only, like function parameters</li>
298          <li><strong>State</strong>: Internal component state, can be modified, re-renders component</li>
299          <li><strong>Props + State</strong>: Most commonly used together for dynamic UI</li>
300        </ul>
301      </div>
302    </div>
303  );
304}
305
306export default App;

Spotted a mistake in this lesson?

Check yourself

Answer the questions from this lesson. Pick an answer to see right away whether it is correct.

  1. 1. What does 'declarative programming' mean in the context of React?

  2. 2. React components can be:

Hands-on tasks in the game

  • Horizontal ordering

    Arrange the path to a dynamic post page in Next.js

  • Code editor

    Create the About page component for the file pages/about.js (export default function About). The page should display an <h1> or <h2> heading with the company name and a <p> paragraph with information about the company.

Useful articles