▶️ Live demo
Try it yourself — interact with the example below.
Loading demo…
🎯 What Is the Date Counter? (Simple Analogy)
Imagine you're planning a trip with a calendar:
BASIC COUNTER (Just Numbers):
┌─────────────────────────────────────────┐
│ 📅 SIMPLE COUNTER │
│ │
│ Count: 0 │
│ [ - ] [ + ] │
│ │
│ Boring! Just numbers! │
│ │
│ In React: │
│ const [count, setCount] = useState(0); │
└─────────────────────────────────────────┘
DATE COUNTER (Real-World Useful):
┌─────────────────────────────────────────┐
│ 📅 DATE COUNTER WITH STEP CONTROL │
│ │
│ Step: [1] [5] [10] ← How big each jump│
│ │
│ Count: -3 │
│ [ - ] [ + ] │
│ │
│ 3 days ago was Monday, June 20 │
│ │
│ Useful! You can plan trips, deadlines, │
│ appointments, anything! │
│ │
│ In React: │
│ const [count, setCount] = useState(0); │
│ const [step, setStep] = useState(1); │
│ // TWO states working together! │
└─────────────────────────────────────────┘
THE MAGIC FORMULA:
┌─────────────────────────────────────────┐
│ TODAY + count days = Target Date │
│ │
│ Example: │
│ Today: June 21 │
│ Count: 5 │
│ Step: 1 │
│ │
│ Result: June 26 (5 days from now) │
│ │
│ With Step = 5: │
│ Click + once → Count = 5 │
│ Result: June 26 (jumped 5 days!) │
│ │
│ The step controls HOW MUCH each │
│ button click changes the count! │
└─────────────────────────────────────────┘
⚠️ The Big Problem: "Two States Working Together"
// ==========================================
// THE "SINGLE STATE" TRAP
// ==========================================
// ❌ WRONG: Only count state, no step control
function BadCounter() {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount(c => c - 1)}>-</button>
<span>{count}</span>
<button onClick={() => setCount(c => c + 1)}>+</button>
<p>{/* How to show the date? */}</p>
</div>
);
}
// Problem 1: Can only add/subtract 1 at a time
// Problem 2: No way to jump by 5 or 10 days
// Problem 3: No date calculation shown
// Problem 4: "0 days" shows as "0 days" not "today"
// ==========================================
// THE SOLUTION: Multiple States + Date Math
// ==========================================
// ✅ CORRECT: Count + Step + Date calculation
function DateCounter() {
// State 1: How many days from today
const [count, setCount] = useState(0);
// State 2: How big each jump is
const [step, setStep] = useState(1);
// Calculate the actual date
const date = new Date(); // Start with today
date.setDate(date.getDate() + count); // Add count days
return (
<div>
{/* Step control */}
<div>
<button onClick={() => setStep(s => s - 1)}>-</button>
<span>Step: {step}</span>
<button onClick={() => setStep(s => s + 1)}>+</button>
</div>
{/* Count control */}
<div>
<button onClick={() => setCount(c => c - step)}>-</button>
<span>Count: {count}</span>
<button onClick={() => setCount(c => c + step)}>+</button>
</div>
{/* Date display */}
<p>
{count === 0 ? 'Today is ' :
count > 0 ? `${count} days from today is ` :
`${Math.abs(count)} days ago was `}
{date.toDateString()}
</p>
</div>
);
}
// What happens:
// Step = 1, Count = 0
// → "Today is Wed Jun 21 2027"
//
// Click Count + (adds step=1):
// Step = 1, Count = 1
// → "1 days from today is Thu Jun 22 2027"
//
// Change Step to 5:
// Step = 5, Count = 1
// → Still shows same date (count didn't change)
//
// Click Count + (adds step=5):
// Step = 5, Count = 6
// → "6 days from today is Tue Jun 27 2027"
// // Jumped 5 days because step = 5!
📋 Complete Visual Examples
Create file: react-date-counter-challenge.js
// ==========================================
// DATE COUNTER CHALLENGE - Complete Guide
// ==========================================
/*
THE CHALLENGE:
┌─────────────────────────────────────────┐
│ Build a counter that: │
│ │
│ 1. Shows current date │
│ 2. Has +/- buttons to change count │
│ 3. Has step control (jump size) │
│ 4. Shows human-readable text: │
│ "Today is..." │
│ "X days from today is..." │
│ "X days ago was..." │
│ │
│ STATES NEEDED: │
│ ┌─────────────────────────────────────┐ │
│ │ count: How many days from today │ │
│ │ step: How much each click changes │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────┘
DATE MATH:
┌─────────────────────────────────────────┐
│ new Date() → Gets TODAY │
│ date.getDate() → Gets day of month (1-31)│
│ date.setDate(day) → Sets day of month │
│ │
│ So: date.setDate(date.getDate() + count)│
│ → Moves the date forward/back by count! │
└─────────────────────────────────────────┘
*/
// ==========================================
// EXAMPLE 1: Basic Counter (Step 1)
// ==========================================
import { useState } from 'react';
function BasicCounter() {
const [count, setCount] = useState(0);
return (
<div style={{ textAlign: 'center', padding: '20px' }}>
<button onClick={() => setCount(c => c - 1)}>-</button>
<span style={{ margin: '0 20px', fontSize: '24px' }}>{count}</span>
<button onClick={() => setCount(c => c + 1)}>+</button>
</div>
);
}
// Visual Flow:
// Initial: count = 0
// [ - ] 0 [ + ]
//
// Click +:
// setCount(0 => 0 + 1) → count = 1
// [ - ] 1 [ + ]
//
// Click + again:
// setCount(1 => 1 + 1) → count = 2
// [ - ] 2 [ + ]
//
// Click -:
// setCount(2 => 2 - 1) → count = 1
// [ - ] 1 [ + ]
// ==========================================
// EXAMPLE 2: Adding the Date
// ==========================================
function CounterWithDate() {
const [count, setCount] = useState(0);
// Create date and add count days
const date = new Date();
date.setDate(date.getDate() + count);
return (
<div style={{ textAlign: 'center', padding: '20px' }}>
<div>
<button onClick={() => setCount(c => c - 1)}>-</button>
<span style={{ margin: '0 20px', fontSize: '24px' }}>{count}</span>
<button onClick={() => setCount(c => c + 1)}>+</button>
</div>
<p style={{ marginTop: '20px', fontSize: '18px' }}>
Date: {date.toDateString()}
</p>
</div>
);
}
// Visual Flow:
// count = 0
// new Date() → June 21, 2027
// + 0 days → June 21, 2027
// "Date: Mon Jun 21 2027"
//
// count = 5
// new Date() → June 21, 2027
// + 5 days → June 26, 2027
// "Date: Sat Jun 26 2027"
//
// count = -3
// new Date() → June 21, 2027
// - 3 days → June 18, 2027
// "Date: Fri Jun 18 2027"
// ==========================================
// EXAMPLE 3: Adding Step Control
// ==========================================
function CounterWithStep() {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1); // NEW STATE!
const date = new Date();
date.setDate(date.getDate() + count);
return (
<div style={{ textAlign: 'center', padding: '20px' }}>
{/* STEP CONTROL */}
<div style={{ marginBottom: '20px' }}>
<button onClick={() => setStep(s => s - 1)}>-</button>
<span style={{ margin: '0 20px' }}>Step: {step}</span>
<button onClick={() => setStep(s => s + 1)}>+</button>
</div>
{/* COUNT CONTROL - Uses step! */}
<div>
<button onClick={() => setCount(c => c - step)}>-</button>
<span style={{ margin: '0 20px', fontSize: '24px' }}>{count}</span>
<button onClick={() => setCount(c => c + step)}>+</button>
</div>
<p style={{ marginTop: '20px', fontSize: '18px' }}>
Date: {date.toDateString()}
</p>
</div>
);
}
// Visual Flow:
// step = 1, count = 0
// Click Count + → count = 0 + 1 = 1
// Click Count + → count = 1 + 1 = 2
// (Adds 1 each time)
//
// Change step = 5:
// step = 5, count = 2
// Click Count + → count = 2 + 5 = 7
// Click Count + → count = 7 + 5 = 12
// (Adds 5 each time!)
//
// Change step = 10:
// step = 10, count = 12
// Click Count - → count = 12 - 10 = 2
// (Subtracts 10 each time!)
// ==========================================
// EXAMPLE 4: Human-Readable Text
// ==========================================
function DateCounter() {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
const date = new Date();
date.setDate(date.getDate() + count);
// Calculate the text to show
let message;
if (count === 0) {
message = 'Today is ';
} else if (count > 0) {
message = `${count} days from today is `;
} else {
message = `${Math.abs(count)} days ago was `;
}
return (
<div style={{ textAlign: 'center', padding: '20px' }}>
<div style={{ marginBottom: '20px' }}>
<button onClick={() => setStep(s => s - 1)}>-</button>
<span style={{ margin: '0 20px' }}>Step: {step}</span>
<button onClick={() => setStep(s => s + 1)}>+</button>
</div>
<div>
<button onClick={() => setCount(c => c - step)}>-</button>
<span style={{ margin: '0 20px', fontSize: '24px' }}>{count}</span>
<button onClick={() => setCount(c => c + step)}>+</button>
</div>
<p style={{ marginTop: '20px', fontSize: '18px' }}>
<span>{message}</span>
<span style={{ fontWeight: 'bold' }}>{date.toDateString()}</span>
</p>
</div>
);
}
// Visual Flow:
// count = 0:
// "Today is Mon Jun 21 2027"
//
// count = 1:
// "1 days from today is Tue Jun 22 2027"
//
// count = 5:
// "5 days from today is Sat Jun 26 2027"
//
// count = -3:
// "3 days ago was Fri Jun 18 2027"
//
// count = -1:
// "1 days ago was Sun Jun 20 2027"
// ==========================================
// EXAMPLE 5: The Nested Ternary (Compact)
// ==========================================
function DateCounterCompact() {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
const date = new Date();
date.setDate(date.getDate() + count);
return (
<div style={{ textAlign: 'center', padding: '20px' }}>
<div style={{ marginBottom: '20px' }}>
<button onClick={() => setStep(s => s - 1)}>-</button>
<span style={{ margin: '0 20px' }}>Step: {step}</span>
<button onClick={() => setStep(s => s + 1)}>+</button>
</div>
<div>
<button onClick={() => setCount(c => c - step)}>-</button>
<span style={{ margin: '0 20px', fontSize: '24px' }}>{count}</span>
<button onClick={() => setCount(c => c + step)}>+</button>
</div>
<p style={{ marginTop: '20px', fontSize: '18px' }}>
{/* Nested ternary - compact but less readable */}
{count === 0
? 'Today is '
: count > 0
? `${count} days from today is `
: `${Math.abs(count)} days ago was `}
<strong>{date.toDateString()}</strong>
</p>
</div>
);
}
// How the nested ternary works:
// count === 0 ?
// YES → 'Today is '
// NO → count > 0 ?
// YES → `${count} days from today is `
// NO → `${Math.abs(count)} days ago was `
🚀 Interactive React Usage Examples
Complete React File: DateCounterMasterClass.jsx
import React, { useState } from 'react';
// ==========================================
// INTERACTIVE DATE COUNTER MASTER CLASS
// ==========================================
function DateCounterMasterClass() {
const [activeDemo, setActiveDemo] = useState('basic');
const demos = {
basic: { title: 'Basic Counter', component: <BasicCounterDemo /> },
date: { title: 'Add Date', component: <DateDemo /> },
step: { title: 'Add Step', component: <StepDemo /> },
final: { title: 'Final Version', component: <FinalDateCounter /> },
breakdown: { title: 'Code Breakdown', component: <CodeBreakdown /> }
};
return (
<div style={{ maxWidth: '900px', margin: '0 auto', padding: '20px', fontFamily: 'Arial, sans-serif' }}>
<header style={{ background: '#e9c46a', color: '#264653', padding: '30px', borderRadius: '10px', marginBottom: '30px' }}>
<h1 style={{ margin: 0 }}>📅 Date Counter Challenge</h1>
<p style={{ margin: '10px 0 0 0', opacity: 0.9 }}>Building a Real-World Component Step by Step</p>
</header>
<nav style={{ display: 'flex', gap: '10px', marginBottom: '30px', flexWrap: 'wrap' }}>
{Object.entries(demos).map(([key, { title }]) => (
<button
key={key}
onClick={() => setActiveDemo(key)}
style={{
padding: '12px 24px',
fontSize: '16px',
border: 'none',
borderRadius: '8px',
cursor: 'pointer',
backgroundColor: activeDemo === key ? '#264653' : '#e0e0e0',
color: activeDemo === key ? 'white' : '#333',
fontWeight: activeDemo === key ? 'bold' : 'normal'
}}
>
{title}
</button>
))}
</nav>
<main style={{ background: '#f8f9fa', padding: '30px', borderRadius: '10px', minHeight: '400px' }}>
{demos[activeDemo].component}
</main>
</div>
);
}
// ==========================================
// DEMO 1: Basic Counter
// ==========================================
function BasicCounterDemo() {
const [count, setCount] = useState(0);
return (
<div>
<h2>Step 1: Basic Counter</h2>
<div style={{ marginBottom: '20px', padding: '15px', background: '#e3f2fd', borderRadius: '8px' }}>
<h4>What we build first:</h4>
<p>Just a number with + and - buttons. No date yet!</p>
</div>
<div style={{
padding: '40px',
background: 'white',
borderRadius: '10px',
textAlign: 'center',
boxShadow: '0 2px 10px rgba(0,0,0,0.1)'
}}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '20px' }}>
<CounterButton onClick={() => setCount(c => c - 1)} label="-" />
<span style={{ fontSize: '48px', fontWeight: 'bold', color: '#264653', minWidth: '80px' }}>
{count}
</span>
<CounterButton onClick={() => setCount(c => c + 1)} label="+" />
</div>
</div>
<div style={{ marginTop: '20px', padding: '15px', background: '#fff3e0', borderRadius: '8px' }}>
<h4>🧠 What's Happening:</h4>
<ol>
<li>State: <code>const [count, setCount] = useState(0)</code></li>
<li>Click - → <code>setCount(c => c - 1)</code></li>
<li>Click + → <code>setCount(c => c + 1)</code></li>
<li>React re-renders with new count!</li>
</ol>
</div>
</div>
);
}
function CounterButton({ onClick, label }) {
return (
<button
onClick={onClick}
style={{
width: '60px',
height: '60px',
fontSize: '28px',
border: 'none',
borderRadius: '50%',
background: '#7950f2',
color: 'white',
cursor: 'pointer',
transition: 'transform 0.1s'
}}
onMouseDown={e => e.target.style.transform = 'scale(0.95)'}
onMouseUp={e => e.target.style.transform = 'scale(1)'}
>
{label}
</button>
);
}
// ==========================================
// DEMO 2: Add Date
// ==========================================
function DateDemo() {
const [count, setCount] = useState(0);
const date = new Date();
date.setDate(date.getDate() + count);
return (
<div>
<h2>Step 2: Add Date Calculation</h2>
<div style={{ marginBottom: '20px', padding: '15px', background: '#e3f2fd', borderRadius: '8px' }}>
<h4>The Date Math:</h4>
<code>const date = new Date();</code><br/>
<code>date.setDate(date.getDate() + count);</code>
</div>
<div style={{
padding: '40px',
background: 'white',
borderRadius: '10px',
textAlign: 'center',
boxShadow: '0 2px 10px rgba(0,0,0,0.1)'
}}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '20px', marginBottom: '30px' }}>
<CounterButton onClick={() => setCount(c => c - 1)} label="-" />
<span style={{ fontSize: '48px', fontWeight: 'bold', color: '#264653', minWidth: '80px' }}>
{count}
</span>
<CounterButton onClick={() => setCount(c => c + 1)} label="+" />
</div>
<div style={{
padding: '20px',
background: '#e8f5e9',
borderRadius: '8px',
fontSize: '20px'
}}>
<span style={{ color: '#666' }}>Date: </span>
<strong style={{ color: '#2e7d32' }}>{date.toDateString()}</strong>
</div>
</div>
<div style={{ marginTop: '20px', padding: '15px', background: '#fff3e0', borderRadius: '8px' }}>
<h4>🧠 How Date Math Works:</h4>
<table style={{ width: '100%', borderCollapse: 'collapse' }}>
<thead>
<tr style={{ background: '#264653', color: 'white' }}>
<th style={{ padding: '10px' }}>count</th>
<th style={{ padding: '10px' }}>Calculation</th>
<th style={{ padding: '10px' }}>Result</th>
</tr>
</thead>
<tbody>
<tr style={{ borderBottom: '1px solid #e0e0e0' }}>
<td style={{ padding: '10px', textAlign: 'center' }}>0</td>
<td style={{ padding: '10px' }}>Today + 0 days</td>
<td style={{ padding: '10px' }}>{new Date().toDateString()}</td>
</tr>
<tr style={{ borderBottom: '1px solid #e0e0e0' }}>
<td style={{ padding: '10px', textAlign: 'center' }}>5</td>
<td style={{ padding: '10px' }}>Today + 5 days</td>
<td style={{ padding: '10px' }}>
{new Date(new Date().setDate(new Date().getDate() + 5)).toDateString()}
</td>
</tr>
<tr>
<td style={{ padding: '10px', textAlign: 'center' }}>-3</td>
<td style={{ padding: '10px' }}>Today - 3 days</td>
<td style={{ padding: '10px' }}>
{new Date(new Date().setDate(new Date().getDate() - 3)).toDateString()}
</td>
</tr>
</tbody>
</table>
</div>
</div>
);
}
// ==========================================
// DEMO 3: Add Step Control
// ==========================================
function StepDemo() {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
const date = new Date();
date.setDate(date.getDate() + count);
return (
<div>
<h2>Step 3: Add Step Control</h2>
<div style={{ marginBottom: '20px', padding: '15px', background: '#e3f2fd', borderRadius: '8px' }}>
<h4>Two States Working Together:</h4>
<p><code>count</code> = current position | <code>step</code> = how much each click moves</p>
</div>
<div style={{
padding: '40px',
background: 'white',
borderRadius: '10px',
textAlign: 'center',
boxShadow: '0 2px 10px rgba(0,0,0,0.1)'
}}>
{/* STEP CONTROL */}
<div style={{ marginBottom: '30px', padding: '20px', background: '#fff3e0', borderRadius: '8px' }}>
<div style={{ fontSize: '14px', color: '#666', marginBottom: '10px' }}>STEP SIZE</div>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '15px' }}>
<CounterButton onClick={() => setStep(s => Math.max(1, s - 1))} label="-" />
<span style={{ fontSize: '32px', fontWeight: 'bold', color: '#e76f51', minWidth: '60px' }}>
{step}
</span>
<CounterButton onClick={() => setStep(s => s + 1)} label="+" />
</div>
<div style={{ marginTop: '10px', fontSize: '14px', color: '#999' }}>
Each click will change count by {step}
</div>
</div>
{/* COUNT CONTROL */}
<div style={{ marginBottom: '30px' }}>
<div style={{ fontSize: '14px', color: '#666', marginBottom: '10px' }}>COUNT</div>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '15px' }}>
<CounterButton onClick={() => setCount(c => c - step)} label="-" />
<span style={{ fontSize: '48px', fontWeight: 'bold', color: '#264653', minWidth: '80px' }}>
{count}
</span>
<CounterButton onClick={() => setCount(c => c + step)} label="+" />
</div>
<div style={{ marginTop: '10px', fontSize: '14px', color: '#999' }}>
{count > 0 ? `+${count}` : count} days from today
</div>
</div>
{/* DATE DISPLAY */}
<div style={{
padding: '20px',
background: '#e8f5e9',
borderRadius: '8px',
fontSize: '20px'
}}>
<span style={{ color: '#666' }}>Date: </span>
<strong style={{ color: '#2e7d32' }}>{date.toDateString()}</strong>
</div>
</div>
<div style={{ marginTop: '20px', padding: '15px', background: '#fff3e0', borderRadius: '8px' }}>
<h4>🧠 How Step Works:</h4>
<p>When step = <strong>{step}</strong>:</p>
<ul>
<li>Click Count + → count becomes {count + step}</li>
<li>Click Count - → count becomes {count - step}</li>
<li>The step controls the "jump size"!</li>
</ul>
</div>
</div>
);
}
// ==========================================
// DEMO 4: Final Version with Text
// ==========================================
function FinalDateCounter() {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
const date = new Date();
date.setDate(date.getDate() + count);
// Calculate message
let message;
if (count === 0) {
message = 'Today is ';
} else if (count > 0) {
message = `${count} days from today is `;
} else {
message = `${Math.abs(count)} days ago was `;
}
function reset() {
setCount(0);
setStep(1);
}
return (
<div>
<h2>Final Date Counter 🎉</h2>
<div style={{ marginBottom: '20px', padding: '15px', background: '#e3f2fd', borderRadius: '8px' }}>
<h4>Complete with human-readable text!</h4>
</div>
<div style={{
padding: '40px',
background: 'white',
borderRadius: '10px',
textAlign: 'center',
boxShadow: '0 2px 10px rgba(0,0,0,0.1)'
}}>
{/* STEP */}
<div style={{ marginBottom: '20px' }}>
<input
type="range"
min="1"
max="10"
value={step}
onChange={e => setStep(Number(e.target.value))}
style={{ width: '100%', maxWidth: '300px' }}
/>
<div style={{ marginTop: '10px', color: '#e76f51', fontWeight: 'bold' }}>
Step: {step}
</div>
</div>
{/* COUNT */}
<div style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
gap: '20px',
marginBottom: '30px'
}}>
<CounterButton onClick={() => setCount(c => c - step)} label="-" />
<input
type="text"
value={count}
onChange={e => setCount(Number(e.target.value))}
style={{
width: '80px',
textAlign: 'center',
fontSize: '24px',
padding: '10px',
border: '2px solid #7950f2',
borderRadius: '8px'
}}
/>
<CounterButton onClick={() => setCount(c => c + step)} label="+" />
</div>
{/* MESSAGE */}
<div style={{
padding: '30px',
background: '#e8f5e9',
borderRadius: '10px',
fontSize: '22px',
lineHeight: '1.6'
}}>
<span style={{ color: '#555' }}>{message}</span>
<br />
<strong style={{ color: '#2e7d32', fontSize: '28px' }}>{date.toDateString()}</strong>
</div>
{/* RESET */}
{(count !== 0 || step !== 1) && (
<button
onClick={reset}
style={{
marginTop: '20px',
padding: '10px 30px',
background: '#ef5350',
color: 'white',
border: 'none',
borderRadius: '5px',
cursor: 'pointer'
}}
>
Reset
</button>
)}
</div>
</div>
);
}
// ==========================================
// DEMO 5: Code Breakdown
// ==========================================
function CodeBreakdown() {
const [highlightedSection, setHighlightedSection] = useState('state');
const sections = {
state: {
title: '1. Create States',
code: `const [count, setCount] = useState(0);
const [step, setStep] = useState(1);`,
explanation: 'Two pieces of state: count (position) and step (jump size)'
},
date: {
title: '2. Calculate Date',
code: `const date = new Date();
date.setDate(date.getDate() + count);`,
explanation: 'Create date object and add count days to it'
},
stepControl: {
title: '3. Step Buttons',
code: `<button onClick={() => setStep(s => s - 1)}>-</button>
<span>Step: {step}</span>
<button onClick={() => setStep(s => s + 1)}>+</button>`,
explanation: 'Buttons to increase/decrease the step size'
},
countControl: {
title: '4. Count Buttons',
code: `<button onClick={() => setCount(c => c - step)}>-</button>
<span>{count}</span>
<button onClick={() => setCount(c => c + step)}>+</button>`,
explanation: 'Buttons use STEP to determine how much to add/subtract'
},
message: {
title: '5. Human Text',
code: `count === 0 ? 'Today is '
: count > 0 ? \`\${count} days from today is \`
: \`\${Math.abs(count)} days ago was \``,
explanation: 'Nested ternary to show "Today", "from today", or "ago"'
}
};
const current = sections[highlightedSection];
return (
<div>
<h2>Code Breakdown 🔍</h2>
<div style={{ display: 'flex', gap: '10px', marginBottom: '20px', flexWrap: 'wrap' }}>
{Object.keys(sections).map(key => (
<button
key={key}
onClick={() => setHighlightedSection(key)}
style={{
padding: '8px 16px',
border: 'none',
borderRadius: '5px',
cursor: 'pointer',
background: highlightedSection === key ? '#264653' : '#e0e0e0',
color: highlightedSection === key ? 'white' : '#333'
}}
>
{sections[key].title}
</button>
))}
</div>
<div style={{ padding: '30px', background: 'white', borderRadius: '10px', border: '2px solid #264653' }}>
<h3 style={{ color: '#264653', marginTop: 0 }}>{current.title}</h3>
<pre style={{
background: '#1e1e1e',
color: '#d4d4d4',
padding: '20px',
borderRadius: '8px',
fontSize: '16px',
overflow: 'auto'
}}>
{current.code}
</pre>
<p style={{ fontSize: '18px', color: '#555', marginTop: '15px' }}>
{current.explanation}
</p>
</div>
</div>
);
}
export default DateCounterMasterClass;
🧠 Memory Aids for Poor Logic Thinking
The "Jumping on a Number Line" Analogy
┌─────────────────────────────────────────────────┐
│ COUNT = YOUR POSITION ON A NUMBER LINE │
│ STEP = HOW FAR YOU JUMP EACH TIME │
│ │
│ Number line: -5 -4 -3 -2 -1 0 1 2 3 │
│ ↑ │
│ You are here (count = -2) │
│ │
│ Step = 3 means you jump 3 spaces: │
│ │
│ Click + : -2 → 1 → 4 → 7 │
│ (Each jump is 3 spaces!) │
│ │
│ Click - : 7 → 4 → 1 → -2 │
│ (Each jump back is 3 spaces!) │
│ │
│ Step = 1 means you jump 1 space: │
│ │
│ Click + : -2 → -1 → 0 → 1 │
│ (Each jump is 1 space!) │
│ │
│ MEMORY TRICK: │
│ count = "Where am I?" │
│ step = "How big are my steps?" │
│ │
│ setCount(c => c + step) = │
│ "New position = Current position + Jump size" │
└─────────────────────────────────────────────────┘
The "Calendar Pages" Analogy
┌─────────────────────────────────────────────────┐
│ DATE MATH = FLIPPING CALENDAR PAGES │
│ │
│ Imagine a desk calendar: │
│ │
│ ┌─────────────────────────────────────────┐ │
│ │ 📅 TODAY: June 21 │ │
│ │ │ │
│ │ count = 0 │ │
│ │ → Don't flip any pages! │ │
│ │ → Still June 21 │ │
│ │ │ │
│ │ count = 3 │ │
│ │ → Flip forward 3 pages: │ │
│ │ June 21 → 22 → 23 → 24 │ │
│ │ → June 24 │ │
│ │ │ │
│ │ count = -2 │ │
│ │ → Flip backward 2 pages: │ │
│ │ June 21 → 20 → 19 │ │
│ │ → June 19 │ │
│ └─────────────────────────────────────────┘ │
│ │
│ The code: │
│ const date = new Date(); ← Open to today │
│ date.setDate(date.getDate() + count); │
│ ↑ │
│ "Go to today's page, then flip 'count' │
│ pages forward or backward" │
│ │
│ Step = how many pages to flip per click! │
│ Step = 5 means flip 5 pages at once! │
└─────────────────────────────────────────────────┘
The "Nested Ternary" Decision Tree
┌─────────────────────────────────────────────────┐
│ NESTED TERNARY = TRAFFIC LIGHTS │
│ │
│ You're at an intersection with 3 roads: │
│ │
│ ┌─────────┐ │
│ │ START │ │
│ └────┬────┘ │
│ │ │
│ count === 0? │
│ / \ │
│ YES NO │
│ │ │ │
│ "Today is" count > 0? │
│ / \ │
│ YES NO │
│ │ │ │
│ "X days "X days │
│ from ago │
│ today" was" │
│ │
│ In code: │
│ count === 0 ? 'Today is ' │
│ : count > 0 ? `${count} days from today is ` │
│ : `${Math.abs(count)} days ago was ` │
│ │
│ MEMORY TRICK: │
│ It's like a choose-your-own-adventure book! │
│ First choice: Is it zero? │
│ If not, second choice: Positive or negative? │
│ │
│ Math.abs(-5) = 5 ← Makes negative positive! │
│ So "-5 days" becomes "5 days ago" │
└─────────────────────────────────────────────────┘
The "Two Dimmers" Analogy
┌─────────────────────────────────────────────────┐
│ TWO STATES = TWO LIGHT DIMMERS │
│ │
│ Imagine controlling room lighting: │
│ │
│ ┌─────────────────────────────────────────┐ │
│ │ 🏠 ROOM WITH TWO DIMMER SWITCHES │ │
│ │ │ │
│ │ Dimmer 1: BRIGHTNESS (count) │ │
│ │ [○──────●──────] 50% │ │
│ │ │ │
│ │ Dimmer 2: SPEED (step) │ │
│ │ [○──●────────] 25% │ │
│ │ │ │
│ │ When you press "Brighter": │ │
│ │ • Brightness increases by SPEED amount │ │
│ │ • Speed doesn't change! │ │
│ │ │ │
│ │ Example: │ │
│ │ Brightness = 30, Speed = 5 │ │
│ │ Press + → Brightness = 35 │ │
│ │ Press + → Brightness = 40 │ │
│ │ │ │
│ │ Change Speed to 10: │ │
│ │ Brightness = 40, Speed = 10 │ │
│ │ Press + → Brightness = 50 │ │
│ │ Press + → Brightness = 60 │ │
│ │ (Now jumps by 10 each time!) │ │
│ └─────────────────────────────────────────┘ │
│ │
│ In React: │
│ const [brightness, setBrightness] = useState(30);│
│ const [speed, setSpeed] = useState(5); │
│ │
│ setBrightness(b => b + speed) │
│ // "New brightness = Current + Speed" │
└─────────────────────────────────────────────────┘
🎓 Practice Exercises
Exercise 1: Build the Basic Counter
Create a counter with + and - buttons:
function Counter() {
// TODO: Add count state
// TODO: Show count
// TODO: Add + and - buttons with inline handlers
return (
<div>
{/* Your code here */}
</div>
);
}
Solution:
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div style={{ textAlign: 'center', padding: '20px' }}>
<button onClick={() => setCount(c => c - 1)}>-</button>
<span style={{ margin: '0 20px', fontSize: '24px' }}>{count}</span>
<button onClick={() => setCount(c => c + 1)}>+</button>
</div>
);
}
Exercise 2: Add the Date
Show the date that is count days from today:
function DateCounter() {
const [count, setCount] = useState(0);
// TODO: Calculate the date
// TODO: Show it below the counter
return (
<div>
<button onClick={() => setCount(c => c - 1)}>-</button>
<span>{count}</span>
<button onClick={() => setCount(c => c + 1)}>+</button>
{/* Show date here */}
</div>
);
}
Solution:
import { useState } from 'react';
function DateCounter() {
const [count, setCount] = useState(0);
// Calculate date
const date = new Date();
date.setDate(date.getDate() + count);
return (
<div style={{ textAlign: 'center', padding: '20px' }}>
<div>
<button onClick={() => setCount(c => c - 1)}>-</button>
<span style={{ margin: '0 20px', fontSize: '24px' }}>{count}</span>
<button onClick={() => setCount(c => c + 1)}>+</button>
</div>
<p style={{ marginTop: '20px', fontSize: '18px' }}>
Date: {date.toDateString()}
</p>
</div>
);
}
Exercise 3: Add Step Control
Add a second state for step size:
function DateCounter() {
// TODO: Add step state
// TODO: Step buttons should change step
// TODO: Count buttons should use step
return (
<div>
{/* Step control */}
{/* Count control */}
{/* Date display */}
</div>
);
}
Solution:
import { useState } from 'react';
function DateCounter() {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
const date = new Date();
date.setDate(date.getDate() + count);
return (
<div style={{ textAlign: 'center', padding: '20px' }}>
{/* Step Control */}
<div style={{ marginBottom: '20px' }}>
<button onClick={() => setStep(s => Math.max(1, s - 1))}>-</button>
<span style={{ margin: '0 20px' }}>Step: {step}</span>
<button onClick={() => setStep(s => s + 1)}>+</button>
</div>
{/* Count Control - Uses step! */}
<div>
<button onClick={() => setCount(c => c - step)}>-</button>
<span style={{ margin: '0 20px', fontSize: '24px' }}>{count}</span>
<button onClick={() => setCount(c => c + step)}>+</button>
</div>
{/* Date Display */}
<p style={{ marginTop: '20px', fontSize: '18px' }}>
Date: {date.toDateString()}
</p>
</div>
);
}
Exercise 4: Add Human-Readable Text
Show "Today is", "X days from today", or "X days ago":
function DateCounter() {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
const date = new Date();
date.setDate(date.getDate() + count);
// TODO: Create message variable with nested ternary
// count === 0 → "Today is "
// count > 0 → "X days from today is "
// count < 0 → "X days ago was "
return (
<div>
{/* Step and Count controls */}
<p>{/* Show message + date */}</p>
</div>
);
}
Solution:
import { useState } from 'react';
function DateCounter() {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
const date = new Date();
date.setDate(date.getDate() + count);
// Human-readable message
const message = count === 0
? 'Today is '
: count > 0
? `${count} days from today is `
: `${Math.abs(count)} days ago was `;
return (
<div style={{ textAlign: 'center', padding: '20px' }}>
<div style={{ marginBottom: '20px' }}>
<button onClick={() => setStep(s => Math.max(1, s - 1))}>-</button>
<span style={{ margin: '0 20px' }}>Step: {step}</span>
<button onClick={() => setStep(s => s + 1)}>+</button>
</div>
<div>
<button onClick={() => setCount(c => c - step)}>-</button>
<span style={{ margin: '0 20px', fontSize: '24px' }}>{count}</span>
<button onClick={() => setCount(c => c + step)}>+</button>
</div>
<p style={{ marginTop: '20px', fontSize: '20px' }}>
<span>{message}</span>
<strong>{date.toDateString()}</strong>
</p>
</div>
);
}
Exercise 5: Add Reset Button
Add a reset button that appears only when not at defaults:
function DateCounter() {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
// TODO: Create reset function
// TODO: Show reset button only when count !== 0 || step !== 1
return (
<div>
{/* Controls */}
{/* Message */}
{/* Reset button (conditional) */}
</div>
);
}
Solution:
import { useState } from 'react';
function DateCounter() {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
const date = new Date();
date.setDate(date.getDate() + count);
const message = count === 0
? 'Today is '
: count > 0
? `${count} days from today is `
: `${Math.abs(count)} days ago was `;
function reset() {
setCount(0);
setStep(1);
}
return (
<div style={{ textAlign: 'center', padding: '20px' }}>
<div style={{ marginBottom: '20px' }}>
<button onClick={() => setStep(s => Math.max(1, s - 1))}>-</button>
<span style={{ margin: '0 20px' }}>Step: {step}</span>
<button onClick={() => setStep(s => s + 1)}>+</button>
</div>
<div>
<button onClick={() => setCount(c => c - step)}>-</button>
<span style={{ margin: '0 20px', fontSize: '24px' }}>{count}</span>
<button onClick={() => setCount(c => c + step)}>+</button>
</div>
<p style={{ marginTop: '20px', fontSize: '20px' }}>
<span>{message}</span>
<strong>{date.toDateString()}</strong>
</p>
{/* Reset button only shows when NOT default */}
{(count !== 0 || step !== 1) && (
<button
onClick={reset}
style={{
marginTop: '20px',
padding: '10px 30px',
background: '#ef5350',
color: 'white',
border: 'none',
borderRadius: '5px',
cursor: 'pointer'
}}
>
Reset
</button>
)}
</div>
);
}
💡 Key Takeaways
| Concept | What It Means | Example | ||
|---|---|---|---|---|
| count state | How many days from today | const [count, setCount] = useState(0) | ||
| step state | How much each click changes | const [step, setStep] = useState(1) | ||
| Date math | Add days to current date | date.setDate(date.getDate() + count) | ||
| Callback with step | Use step in count update | setCount(c => c + step) | ||
| Nested ternary | Three-way text decision | count === 0 ? 'Today' : count > 0 ? 'Future' : 'Past' | ||
| Math.abs() | Make negative positive | Math.abs(-5) → 5 | ||
| Conditional reset | Show button only when needed | `(count !== 0 \ | \ | step !== 1) && <button>` |
The Complete Pattern:
function DateCounter() {
// 1. States
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
// 2. Derived value (date calculation)
const date = new Date();
date.setDate(date.getDate() + count);
// 3. Derived text (ternary)
const message = count === 0 ? 'Today is '
: count > 0 ? `${count} days from today is `
: `${Math.abs(count)} days ago was `;
return (
<div>
{/* 4. Step control */}
<button onClick={() => setStep(s => s - 1)}>-</button>
<span>Step: {step}</span>
<button onClick={() => setStep(s => s + 1)}>+</button>
{/* 5. Count control (uses step!) */}
<button onClick={() => setCount(c => c - step)}>-</button>
<span>{count}</span>
<button onClick={() => setCount(c => c + step)}>+</button>
{/* 6. Display */}
<p>{message}{date.toDateString()}</p>
</div>
);
}
Golden Rules:
- One state per independent changing thing —
countandstepare separate - Use callbacks when based on current state —
setCount(c => c + step) - Date math:
setDate(getDate() + count)— This moves the date forward/back - Nested ternary for 3+ text options — Today / future / past
Math.abs()for "X days ago" — Makes negative numbers positive- Show reset only when needed — Conditional rendering with
&& - Inline handlers for simple logic —
onClick={() => setCount(c => c + step)}
One Sentence Summary: > "The Date Counter uses two independent pieces of state—count for your position on the timeline and step for how far each button click jumps—where the count buttons use the step value in their callback functions to calculate the new count, the date is derived by adding the count to today's date with setDate(getDate() + count), and a nested ternary displays human-readable text like 'Today is', 'X days from today', or 'X days ago' based on whether the count is zero, positive, or negative!"