Next.js course · Module 1: Next.js Configuration
Component System - Client and Server Components
In this lesson10
In Quantum Metropolis, quantum system architects always have to make fundamental decisions: which processes to run on central quantum processors (for tasks requiring the highest computational power), and which on citizens' end devices (for instant interactivity). This dichotomy perfectly reflects the revolutionary change that the App Router introduced in Next.js 13 and that Next.js 16 develops further - the division into Server Components and Client Components.
The React Server Components Revolution
React Server Components (RSC) represent the biggest paradigm shift in React since the introduction of Hooks. Before their appearance, all React components were rendered on the server or client as a cohesive whole. Now we can create applications where some components are rendered exclusively on the server, others on the client, and data and UI structures flow seamlessly between them.
It's like the difference between traditional transport systems in Quantum Metropolis, where vehicles move only along specific routes, and the new quantum transport system, where matter can be teleported directly to its destination.
Server Components - Basics
In the App Router of Next.js 16, all components are Server Components by default, unless we explicitly mark them as Client Components.
Server Components are rendered on the server and don't send any JavaScript to the browser. It's like the quantum computing processors of Quantum Metropolis, which perform complex calculations and transmit only the final results to citizens' devices.
Advantages of Server Components:
- Access to server resources - direct access to databases, file system, and other server resources
- Security - sensitive data and logic remain on the server
- Automatic code splitting - only necessary code is sent to the client
- Smaller JavaScript bundle size - no need to send rendering code
- Better SEO - faster static rendering
- Better first load performance - less JavaScript to download and execute
Server Component Example:
1// app/dashboard/stats/page.tsx - Server Component (by default)
2export default async function StatsPage() {
3 // This code runs ONLY on the server
4 const stats = await fetchQuantumSystemStats();
5
6 return (
7 <section className="quantum-stats">
8 <h1>Quantum Systems Statistics</h1>
9 <div className="stats-grid">
10 {stats.map(stat => (
11 <StatCard key={stat.id} name={stat.name} value={stat.value} />
12 ))}
13 </div>
14 </section>
15 );
16}Note several important aspects:
- Using async/await directly in the component - this is only possible in Server Components
- No use of React hooks (useState, useEffect, etc.) - they are not available in Server Components
- No event handling - Server Components cannot handle user events
Client Components - Basics
Client Components provide interactivity: on the first visit Next.js pre-renders them to HTML on the server, then they are hydrated in the browser and keep running on the client. To mark a component as a Client Component, we add the "use client" directive at the top of the file.
This process is called hydration: in the browser, React attaches event handlers to the HTML that was rendered on the server earlier. Only after hydration do buttons respond to clicks, and useEffect effects run after it.
It's like the personal quantum devices of Quantum Metropolis citizens - lighter, but instantly responsive to user actions.
Advantages of Client Components:
- Interactivity - handling user events (clicks, text input, etc.)
- React hooks - ability to use useState, useEffect, useContext, and other hooks
- Access to browser APIs - window, document, localStorage, etc.
- Client-side effects - animations, real-time interactions
Client Component Example:
1// app/dashboard/interactive-controls.tsx
2"use client"; // This directive marks the client component
3
4import { useState, useEffect } from 'react';
5
6export default function InteractiveControls() {
7 // This code runs in the user's browser
8 const [activeSystem, setActiveSystem] = useState('energy');
9 const [status, setStatus] = useState('idle');
10
11 useEffect(() => {
12 // Effects run only on the client
13 const timer = setTimeout(() => {
14 setStatus('ready');
15 }, 1000);
16
17 return () => clearTimeout(timer);
18 }, []);
19
20 return (
21 <div className="control-panel">
22 <h2>System: {activeSystem}</h2>
23 <p>Status: {status}</p>
24 <div className="button-group">
25 <button onClick={() => setActiveSystem('transport')}>
26 Transport
27 </button>
28 <button onClick={() => setActiveSystem('energy')}>
29 Energy
30 </button>
31 <button onClick={() => setActiveSystem('security')}>
32 Security
33 </button>
34 </div>
35 </div>
36 );
37}Key aspects:
- The
"use client"directive at the beginning of the file - Using React hooks (useState, useEffect)
- Event handling (onClick)
Combining Server and Client Components
The most powerful feature of the new model is the ability to combine Server and Client Components in a single application. Server Components can render Client Components, but not the other way around (with some exceptions using patterns). It's like the hybrid transport system of Quantum Metropolis, where main routes are served by quantum teleportation, and the last mile by personal vehicles.
Example of combining components:
1// app/dashboard/page.tsx - Server Component
2export default async function DashboardPage() {
3 // This code runs ONLY on the server
4 const dashboardData = await fetchDashboardData();
5
6 return (
7 <main className="quantum-dashboard">
8 <h1>Quantum Metropolis Control Panel</h1>
9
10 {/* Server Component */}
11 <SystemStatusPanel systemsData={dashboardData.systems} />
12
13 {/* Client Component (imported and used in Server Component) */}
14 <InteractiveControls />
15 </main>
16 );
17}1// app/dashboard/system-status-panel.tsx - Server Component (by default)
2export default function SystemStatusPanel({ systemsData }) {
3 return (
4 <div className="system-status-panel">
5 <h2>System Status</h2>
6 <div className="status-grid">
7 {systemsData.map(system => (
8 <SystemStatusCard key={system.id} system={system} />
9 ))}
10 </div>
11 </div>
12 );
13}1// app/dashboard/system-status-card.tsx - Server Component (by default)
2import { StatusIndicator } from './status-indicator';
3
4export default function SystemStatusCard({ system }) {
5 return (
6 <div className="status-card">
7 <h3>{system.name}</h3>
8 <p>Performance: {system.performance}%</p>
9
10 {/* Client Component used in Server Component */}
11 <StatusIndicator status={system.status} />
12 </div>
13 );
14}1// app/dashboard/status-indicator.tsx - Client Component
2"use client";
3
4import { useState, useEffect } from 'react';
5
6export function StatusIndicator({ status }) {
7 const [blinking, setBlinking] = useState(false);
8
9 useEffect(() => {
10 const interval = setInterval(() => {
11 setBlinking(prev => !prev);
12 }, 500);
13
14 return () => clearInterval(interval);
15 }, []);
16
17 return (
18 <div className={`status-indicator ${status} ${blinking ? 'blink' : ''}`}>
19 {status === 'active' ? 'Active' : 'Inactive'}
20 </div>
21 );
22}Optimization Strategies When Designing Components
Properly deciding which components should be Server Components and which should be Client Components is crucial for application performance. Here are some strategies to help you make these decisions:
1. Server Component as the Default Choice
Always start with Server Components unless you need features available only in Client Components. This is similar to the approach in Quantum Metropolis, where central computing units are used by default unless instant interactivity is needed.
2. Granular Interactivity
Instead of marking an entire large component as "use client", extract only the interactive parts into separate Client Components, leaving the rest as Server Components.
Before optimization:
1// LESS OPTIMAL - entire component is a Client Component
2"use client";
3import { useState } from 'react';
4
5export default function ControlPanel() {
6 const [activeTab, setActiveTab] = useState('overview');
7
8 return (
9 <div className="control-panel">
10 <h2>Control Panel</h2>
11 <p>This panel allows you to manage quantum systems.</p>
12
13 <div className="tabs">
14 <button onClick={() => setActiveTab('overview')}>Overview</button>
15 <button onClick={() => setActiveTab('settings')}>Settings</button>
16 </div>
17
18 <div className="tab-content">
19 {activeTab === 'overview' ? (
20 <OverviewContent /> // Lots of static content
21 ) : (
22 <SettingsContent /> // Lots of static content
23 )}
24 </div>
25 </div>
26 );
27}After optimization:
1// BETTER - split into Client and Server Components
2
3// control-panel.tsx - Server Component
4import { TabController } from './tab-controller';
5import { OverviewContent } from './overview-content';
6import { SettingsContent } from './settings-content';
7
8export default function ControlPanel() {
9 return (
10 <div className="control-panel">
11 <h2>Control Panel</h2>
12 <p>This panel allows you to manage quantum systems.</p>
13
14 {/* Only TabController is a Client Component; the tab contents stay on the server */}
15 <TabController overview={<OverviewContent />} settings={<SettingsContent />} />
16 </div>
17 );
18}
19
20// tab-controller.tsx - Client Component
21"use client";
22import { useState, type ReactNode } from 'react';
23
24export function TabController({ overview, settings }: { overview: ReactNode; settings: ReactNode }) {
25 const [activeTab, setActiveTab] = useState('overview');
26
27 return (
28 <>
29 <div className="tabs">
30 <button onClick={() => setActiveTab('overview')}>Overview</button>
31 <button onClick={() => setActiveTab('settings')}>Settings</button>
32 </div>
33
34 <div className="tab-content">
35 {activeTab === 'overview' ? overview : settings}
36 </div>
37 </>
38 );
39}A component imported in a file with "use client" becomes a Client Component too. That is why the Server Component ControlPanel imports OverviewContent and SettingsContent and passes them to TabController as props, just like children.
3. "Container and Presentation" Pattern
Use Server Components as "containers" for fetching data and organization, and Client Components as "presentation components" responsible for interactivity.
1// products-container.tsx - Server Component (container)
2export default async function ProductsContainer() {
3 const products = await fetchProducts();
4
5 return <ProductsList products={products} />;
6}
7
8// products-list.tsx - Client Component (presentation)
9"use client";
10import { useState } from 'react';
11
12export function ProductsList({ products }) {
13 const [sortBy, setSortBy] = useState('name');
14 const sortedProducts = [...products].sort((a, b) =>
15 sortBy === 'price' ? a.price - b.price : a.name.localeCompare(b.name)
16 );
17
18 return (
19 <div>
20 <div className="sorting">
21 <button onClick={() => setSortBy('name')}>Sort by name</button>
22 <button onClick={() => setSortBy('price')}>Sort by price</button>
23 </div>
24
25 <ul className="products">
26 {sortedProducts.map(product => (
27 <li key={product.id}>{product.name} - {product.price}</li>
28 ))}
29 </ul>
30 </div>
31 );
32}Data Flow Between Server and Client Components
Passing data between server and client requires a special approach. In the RSC model, props flow down the component tree from server to client; in the other direction the client sends data by calling Server Actions (you will meet them in a moment). It's like quantum channels in Quantum Metropolis - orders flow from the central hub to personal devices, and reports come back through a separate channel.
Passing Data to Client Components:
1// server-component.tsx - Server Component
2async function ServerComponent() {
3 const data = await fetchSensitiveData();
4
5 // Pass processed data to client
6 return <ClientComponent processedData={data.publicPart} />;
7}
8
9// client-component.tsx - Client Component
10"use client";
11
12export function ClientComponent({ processedData }) {
13 // Using data passed from the server
14 return <div>{processedData.map(item => <p key={item.id}>{item.name}</p>)}</div>;
15}Handling User Actions from Client Components:
When a Client Component needs to perform an action that involves the server, we use Server Actions or Route Handlers (route.ts files; in the Pages Router their counterpart is API Routes).
Using Server Actions (stable since Next.js 14):
1// actions.js - Server Actions
2"use server";
3
4export async function updateSystemStatus(systemId, newStatus) {
5 // This function runs on the server
6 await database.systems.update(systemId, { status: newStatus });
7 return { success: true };
8}
9
10// client-component.tsx - Client Component
11"use client";
12import { useState } from 'react';
13import { updateSystemStatus } from './actions';
14
15export function StatusToggle({ systemId, initialStatus }) {
16 const [status, setStatus] = useState(initialStatus);
17
18 async function handleToggle() {
19 const newStatus = status === 'active' ? 'inactive' : 'active';
20 const result = await updateSystemStatus(systemId, newStatus);
21
22 if (result.success) {
23 setStatus(newStatus);
24 }
25 }
26
27 return (
28 <button onClick={handleToggle}>
29 {status === 'active' ? 'Deactivate' : 'Activate'}
30 </button>
31 );
32}Differences in Reloading and Navigation
In the traditional React model, page reloading or navigation often meant restarting the entire application. In the React Server Components model, navigation is more optimal:
- Server Components are re-rendered on the server during navigation
- Client Components in shared layouts keep their state during navigation; components of the page you leave are unmounted by default
- Page transitions are smoother thanks to the "instant navigation" mechanism
It's like the advanced quantum switches in Quantum Metropolis - they allow instant transitions between different layouts without interrupting system operations.
Common Mistakes and Pitfalls
1. Using React hooks in Server Components
1// WRONG - Server Component trying to use React hooks
2export default function ServerComponent() {
3 // This will cause an error!
4 const [count, setCount] = useState(0);
5
6 return <div>Count: {count}</div>;
7}2. Attempting to access browser APIs in Server Components
1// WRONG - Server Component trying to use browser APIs
2export default function ServerComponent() {
3 // This will cause an error! (ReferenceError: window is not defined)
4 const windowWidth = window.innerWidth;
5
6 return <div>Width: {windowWidth}px</div>;
7}3. Passing functions from Server Components to Client Components
1// WRONG - Server Component passes a regular function to a Client Component
2// app/page.tsx (Server Component)
3import ClientButton from './client-button';
4
5export default function Page() {
6 const handleClick = () => console.log("Clicked!");
7
8 // This won't work! Props passed to a Client Component must be serializable
9 return <ClientButton onClick={handleClick} />;
10}Server Actions are the exception: you can pass a function marked with "use server" to a Client Component.
Advanced Patterns for Using Server and Client Components
1. Provider Pattern
If you need to share state between different Client Components, use a Client Provider at a high level. This is similar to central synchronization units in Quantum Metropolis, which coordinate the actions of different personal devices.
1// providers.tsx - Client Component
2"use client";
3import { createContext, useState } from 'react';
4
5export const ThemeContext = createContext({ theme: 'light', toggleTheme: () => {} });
6
7export function ThemeProvider({ children }) {
8 const [theme, setTheme] = useState('light');
9 const toggleTheme = () => setTheme(prev => prev === 'light' ? 'dark' : 'light');
10
11 return (
12 <ThemeContext.Provider value={{ theme, toggleTheme }}>
13 {children}
14 </ThemeContext.Provider>
15 );
16}1// layout.tsx - Server Component
2import { ThemeProvider } from './providers';
3
4export default function RootLayout({ children }: { children: React.ReactNode }) {
5 return (
6 <html>
7 <body>
8 <ThemeProvider>
9 {children}
10 </ThemeProvider>
11 </body>
12 </html>
13 );
14}2. "Lifting State Up" Pattern
When you have several Client Components that need access to the same state, lift the state to a common Client Component ancestor, not to a Server Component.
1// parent.tsx - Server Component
2export default function ParentServerComponent() {
3 return <ClientParent />;
4}
5
6// client-parent.tsx - Client Component (common ancestor)
7"use client";
8import { useState } from 'react';
9
10export function ClientParent() {
11 const [sharedState, setSharedState] = useState('initial');
12
13 return (
14 <div>
15 <ClientChildA sharedState={sharedState} setSharedState={setSharedState} />
16 <ClientChildB sharedState={sharedState} />
17 </div>
18 );
19}3. Strategic Use of Suspense
Use the Suspense component to manage loading states in a hybrid application:
1// page.tsx - Server Component
2import { Suspense } from 'react';
3
4export default function Page() {
5 return (
6 <div>
7 <h1>Quantum Metropolis System Data</h1>
8
9 <Suspense fallback={<div>Loading data...</div>}>
10 <AsyncDataComponent />
11 </Suspense>
12 </div>
13 );
14}
15
16// async-data-component.tsx - Server Component with asynchronous code
17async function AsyncDataComponent() {
18 // This component can be suspended during loading
19 const data = await fetchData();
20
21 return <div>{/* Rendering data */}</div>;
22}Summary
The component system in Next.js 16 based on React Server Components is a revolutionary change that combines the advantages of server rendering with client-side interactivity. Just as in Quantum Metropolis, where quantum teleportation and personal vehicles create a hybrid transport system, in Next.js server and client components work together, creating an efficient, scalable, and user-friendly interface.
When designing Next.js 16 applications:
- Use Server Components by default for better performance and security
- Switch to Client Components only when you need interactivity, hooks, or browser APIs
- Split components granularly to minimize the amount of JavaScript sent to the client
- Remember the direction of props - from server to client (you send data the other way with Server Actions)
- Use Server Actions for form processing and other user actions
Proper use of Server and Client Components will allow you to create next-generation Next.js applications that combine fast loading, SEO performance, and rich user interfaces - without the compromises that were necessary in traditional React applications.
In the next lesson, we will move to practice and create our first "Hello World" application using Next.js 16 and App Router, where we'll apply the knowledge gained about Server and Client Components.
Code for this lesson: App.tsx
1// Hooks - useState and useEffect - Metropolis Quantum
2import React, { useState, useEffect } from 'react';
3
4console.log("React Hooks - useState and useEffect");
5console.log("Quantum Systems Management\n");
6
7// ==========================================
8// 1. useState - State Management
9// ==========================================
10
11function QuantumReactor() {
12 const [temperature, setTemperature] = useState<number>(20);
13 const [pressure, setPressure] = useState<number>(100);
14 const [status, setStatus] = useState<'stable' | 'warning' | 'critical'>('stable');
15
16 // useEffect - monitor temperature and pressure changes
17 useEffect(() => {
18 console.log(`Temperature: ${temperature}°C, Pressure: ${pressure} kPa`);
19
20 // Determine status based on values
21 if (temperature > 80 || pressure > 150) {
22 setStatus('critical');
23 } else if (temperature > 60 || pressure > 120) {
24 setStatus('warning');
25 } else {
26 setStatus('stable');
27 }
28 }, [temperature, pressure]); // Called when temperature or pressure change
29
30 const getStatusColor = () => {
31 switch(status) {
32 case 'stable': return '#4caf50';
33 case 'warning': return '#ff9800';
34 case 'critical': return '#f44336';
35 }
36 };
37
38 return (
39 <div style={{
40 background: 'rgba(255, 255, 255, 0.1)',
41 padding: '20px',
42 borderRadius: '12px',
43 border: `2px solid ${getStatusColor()}`
44 }}>
45 <h2 style={{ color: getStatusColor() }}>
46 Quantum Reactor - {status.toUpperCase()}
47 </h2>
48
49 <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '20px', marginTop: '20px' }}>
50 <div>
51 <h4>Temperature: {temperature}°C</h4>
52 <input
53 type="range"
54 min="0"
55 max="100"
56 value={temperature}
57 onChange={(e) => setTemperature(Number(e.target.value))}
58 style={{ width: '100%' }}
59 />
60 </div>
61
62 <div>
63 <h4>Pressure: {pressure} kPa</h4>
64 <input
65 type="range"
66 min="50"
67 max="200"
68 value={pressure}
69 onChange={(e) => setPressure(Number(e.target.value))}
70 style={{ width: '100%' }}
71 />
72 </div>
73 </div>
74 </div>
75 );
76}
77
78// ==========================================
79// 2. useEffect - Side Effects
80// ==========================================
81
82function QuantumClock() {
83 const [time, setTime] = useState<Date>(new Date());
84 const [quantumTime, setQuantumTime] = useState<number>(0);
85
86 // useEffect for clock - runs after component mounts
87 useEffect(() => {
88 console.log("Quantum Clock initiated");
89
90 const interval = setInterval(() => {
91 setTime(new Date());
92 setQuantumTime(prev => prev + 1);
93 }, 1000);
94
95 // Cleanup function - called on unmount
96 return () => {
97 console.log("Quantum Clock stopped");
98 clearInterval(interval);
99 };
100 }, []); // Empty array = run once after mounting
101
102 return (
103 <div style={{
104 background: 'rgba(124, 77, 255, 0.2)',
105 padding: '20px',
106 borderRadius: '12px',
107 textAlign: 'center'
108 }}>
109 <h3 style={{ color: '#7c4dff' }}>Quantum Time Portal</h3>
110 <div style={{ fontSize: '2rem', margin: '20px 0', color: '#64ffda' }}>
111 {time.toLocaleTimeString()}
112 </div>
113 <div style={{ color: '#b0bec5' }}>
114 Quantum Seconds: {quantumTime}
115 </div>
116 </div>
117 );
118}
119
120// ==========================================
121// 3. Multiple useEffect Hooks
122// ==========================================
123
124function DataMonitor() {
125 const [data, setData] = useState<number[]>([]);
126 const [average, setAverage] = useState<number>(0);
127 const [trend, setTrend] = useState<'up' | 'down' | 'stable'>('stable');
128
129 // Effect 1: Generate new data every second
130 useEffect(() => {
131 const interval = setInterval(() => {
132 const newValue = Math.floor(Math.random() * 100);
133 setData(prev => [...prev.slice(-9), newValue]); // Keep the last 10 values
134 }, 1000);
135
136 return () => clearInterval(interval);
137 }, []);
138
139 // Effect 2: Calculate average when data changes
140 useEffect(() => {
141 if (data.length > 0) {
142 const avg = data.reduce((a, b) => a + b, 0) / data.length;
143 setAverage(avg);
144 console.log(`New average: ${avg.toFixed(2)}`);
145 }
146 }, [data]);
147
148 // Effect 3: Determine trend
149 useEffect(() => {
150 if (data.length >= 2) {
151 const lastTwo = data.slice(-2);
152 if (lastTwo[1] > lastTwo[0]) setTrend('up');
153 else if (lastTwo[1] < lastTwo[0]) setTrend('down');
154 else setTrend('stable');
155 }
156 }, [data]);
157
158 const getTrendIcon = () => {
159 switch(trend) {
160 case 'up': return '▲';
161 case 'down': return '▼';
162 case 'stable': return '→';
163 }
164 };
165
166 return (
167 <div style={{
168 background: 'rgba(255, 255, 255, 0.1)',
169 padding: '20px',
170 borderRadius: '12px'
171 }}>
172 <h3 style={{ color: '#64ffda' }}>Data Stream Monitor</h3>
173
174 <div style={{ display: 'flex', gap: '5px', marginTop: '15px', height: '100px', alignItems: 'flex-end' }}>
175 {data.map((value, index) => (
176 <div
177 key={index}
178 style={{
179 flex: 1,
180 height: `${value}%`,
181 background: 'linear-gradient(to top, #7c4dff, #64ffda)',
182 borderRadius: '4px 4px 0 0'
183 }}
184 />
185 ))}
186 </div>
187
188 <div style={{ marginTop: '20px', display: 'flex', justifyContent: 'space-around' }}>
189 <div>
190 <div style={{ color: '#b0bec5', fontSize: '0.9rem' }}>Average</div>
191 <div style={{ color: '#64ffda', fontSize: '1.5rem', fontWeight: 'bold' }}>
192 {average.toFixed(1)}
193 </div>
194 </div>
195 <div>
196 <div style={{ color: '#b0bec5', fontSize: '0.9rem' }}>Trend</div>
197 <div style={{ fontSize: '1.5rem' }}>
198 {getTrendIcon()}
199 </div>
200 </div>
201 </div>
202 </div>
203 );
204}
205
206// ==========================================
207// Main App
208// ==========================================
209function App() {
210 useEffect(() => {
211 console.log("Quantum Systems Dashboard initialized");
212 }, []);
213
214 return (
215 <div style={{
216 padding: '20px',
217 background: 'linear-gradient(135deg, #0f0f23 0%, #1a1a2e 100%)',
218 minHeight: '100vh',
219 color: 'white'
220 }}>
221 <h1 style={{ textAlign: 'center', color: '#64ffda' }}>
222 React Hooks - useState & useEffect
223 </h1>
224
225 <div style={{ display: 'grid', gap: '20px', marginTop: '30px' }}>
226 <QuantumReactor />
227 <QuantumClock />
228 <DataMonitor />
229 </div>
230
231 <div style={{
232 marginTop: '30px',
233 background: 'rgba(100, 255, 218, 0.1)',
234 padding: '20px',
235 borderRadius: '10px',
236 borderLeft: '4px solid #64ffda'
237 }}>
238 <h3>useEffect Tips:</h3>
239 <ul style={{ lineHeight: '1.8' }}>
240 <li>[] (empty array) = run once after mounting</li>
241 <li>[dep1, dep2] = run when dependencies change</li>
242 <li>No array = run after every render</li>
243 <li>Return function = cleanup before unmounting</li>
244 <li>You can have multiple useEffects in a component</li>
245 </ul>
246 </div>
247 </div>
248 );
249}
250
251export 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. Props in React are:
2. State in React is:
3. The useState hook is used for:
Hands-on tasks in the game
- Code editor
Create an async Server Component ImplantDashboard (export default). Above the component, define an async function getImplants() that returns an array of 3 implants shaped { id, name, status }. In the component, fetch the data with const implants = await getImplants(), then display them in a <ul>: each implant as an <li key={implant.id}> with its name and status.
- Code editor
Create a Client Component NeuralVisualizer (export default): add 'use client' at the top of the file, keep the activity in useState (a boolean, false at first), add an "Activate Neural Link" button that changes the state, and display "Status: ACTIVE" or "Status: INACTIVE".
- Click in order
Arrange the syntax for exporting a Server Component in Next.js
- Code editor
Create a Greeting component that accepts a 'name' prop and displays a personalized welcome message
- Vertical ordering
Arrange the steps of SSR page rendering in Next.js
- Code editor
Create a Counter component that displays a counter (useState, initial value 0) and a button that increases the counter by 1 on each click.
- Click in order
Arrange the syntax for destructuring the useState hook
- Code editor
Create a HolographicInterface component: export a default function that returns a div with class 'dashboard-panel', an h1 heading 'Next.js Dashboard', and a paragraph with system status.
- Code editor
Create a login page component LoginPage (export default). Add 'use client' at the top of the file. Return a <form> with an email field (<input type="email">), a password field (<input type="password">) and a "Log in" button (<button type="submit">). In the onSubmit handler, call event.preventDefault() so the page does not reload.