vite-react-kek
v1.0.0
Published
* JSX and component thinking * Props * State * `useState` * Conditional rendering * List rendering * Event handling * Controlled interaction patterns * Derived UI * Lifting state up * `useEffect` * `useRef` * `useMemo` * `useCallback` * Cont
Readme
- JSX and component thinking
- Props
- State
useState- Conditional rendering
- List rendering
- Event handling
- Controlled interaction patterns
- Derived UI
- Lifting state up
useEffectuseRefuseMemouseCallback- Context API
- Component composition
- Reusable child components
- Dynamic UI behavior
- Basic optimization thinking
Problem 1: Email Inbox Category Switcher
Problem Statement
You are building a simple Inbox Category Switcher for an email application. The inbox is divided into three categories:
- Primary
- Promotions
- Updates
Users should be able to click on a category tab and see only the emails that belong to that category. The selected category should be visually highlighted so that users know which section they are viewing.
This is a realistic feature because almost every email product, productivity dashboard, or messaging tool has some kind of categorized view. The goal of this problem is to help students practice state-driven filtering, list rendering, conditional styling, and reusable component thinking in React.
Functional Requirements
Show three category buttons:
- Primary
- Promotions
- Updates
Maintain a list of emails, where each email contains:
idsubjectsendercategory
By default, show emails from the
Primarycategory.Clicking a category button should:
- update the active category
- re-render the visible emails
The active category button should look visually different.
Each visible email should show:
- subject
- sender
If a category contains no emails, show:
No emails in this category
Use a child component to render each email item.
Concepts Covered
- State
- Props
useState- Conditional rendering
- List rendering
- Derived UI
Hints
- Keep the currently active category in state.
- Use
filter()to derive the visible emails. - Pass email data as props into a reusable child component.
- Active button styling should depend on the selected category.
- This is a great example of deriving UI from state rather than storing duplicate values.
Code Stub
import React, { useState } from "react";
const emails = [
{ id: 1, subject: "Project kickoff scheduled", sender: "Manager", category: "Primary" },
{ id: 2, subject: "50% off on travel bags", sender: "ShopEase", category: "Promotions" },
{ id: 3, subject: "Your monthly usage report", sender: "CloudPanel", category: "Updates" },
{ id: 4, subject: "Interview round details", sender: "Recruiter", category: "Primary" },
];
function EmailItem({ email }) {
return (
<div style={{ border: "1px solid #ddd", padding: "10px", marginBottom: "10px" }}>
<h4>{email.subject}</h4>
<p>From: {email.sender}</p>
</div>
);
}
export default function InboxCategorySwitcher() {
const [activeCategory, setActiveCategory] = useState("Primary");
// TODO: derive visible emails
const visibleEmails = emails;
return (
<div style={{ padding: "20px" }}>
<h2>Email Inbox</h2>
<button onClick={() => setActiveCategory("Primary")}>Primary</button>
<button onClick={() => setActiveCategory("Promotions")} style={{ marginLeft: "10px" }}>
Promotions
</button>
<button onClick={() => setActiveCategory("Updates")} style={{ marginLeft: "10px" }}>
Updates
</button>
<div style={{ marginTop: "20px" }}>
{visibleEmails.map((email) => (
<EmailItem key={email.id} email={email} />
))}
</div>
</div>
);
}Full Solution
import React, { useState } from "react";
const emails = [
{ id: 1, subject: "Project kickoff scheduled", sender: "Manager", category: "Primary" },
{ id: 2, subject: "50% off on travel bags", sender: "ShopEase", category: "Promotions" },
{ id: 3, subject: "Your monthly usage report", sender: "CloudPanel", category: "Updates" },
{ id: 4, subject: "Interview round details", sender: "Recruiter", category: "Primary" },
];
function EmailItem({ email }) {
return (
<div style={{ border: "1px solid #ddd", padding: "10px", marginBottom: "10px", borderRadius: "8px" }}>
<h4>{email.subject}</h4>
<p>From: {email.sender}</p>
</div>
);
}
export default function InboxCategorySwitcher() {
const [activeCategory, setActiveCategory] = useState("Primary");
const visibleEmails = emails.filter(
(email) => email.category === activeCategory
);
const getButtonStyle = (category) => ({
backgroundColor: activeCategory === category ? "#ddd" : "white",
padding: "8px 12px",
});
return (
<div style={{ padding: "20px" }}>
<h2>Email Inbox</h2>
<button
onClick={() => setActiveCategory("Primary")}
style={getButtonStyle("Primary")}
>
Primary
</button>
<button
onClick={() => setActiveCategory("Promotions")}
style={{ ...getButtonStyle("Promotions"), marginLeft: "10px" }}
>
Promotions
</button>
<button
onClick={() => setActiveCategory("Updates")}
style={{ ...getButtonStyle("Updates"), marginLeft: "10px" }}
>
Updates
</button>
<div style={{ marginTop: "20px" }}>
{visibleEmails.length === 0 ? (
<p>No emails in this category</p>
) : (
visibleEmails.map((email) => <EmailItem key={email.id} email={email} />)
)}
</div>
</div>
);
}Test Cases
Action: App loads Expected: Only
Primaryemails are shown.Action: User clicks
PromotionsExpected: Only promotion emails are displayed.Action: User clicks
UpdatesExpected: Only update emails are displayed.Action: User switches back to
PrimaryExpected: Primary emails appear again.Action: Active category is
PromotionsExpected: Promotions button is visually highlighted.Action: Active category changes Expected: Previous active button loses highlight.
Action: Category contains no emails Expected:
No emails in this categoryis shown.Action: Each email item renders Expected: Subject and sender are both visible.
Action: User switches categories multiple times Expected: List always matches the selected category.
Action: App renders email items Expected: Each email uses its
idas React key.
Problem 2: Playlist Song Highlighter
Problem Statement
You are building a Playlist Song Highlighter for a music streaming application. Users should be able to click on a song from the playlist and see which track is currently selected.
The selected song should be highlighted in the list, and a details panel should show the currently selected song’s title and artist. This kind of interaction is very common in media applications, music players, podcast platforms, and video playlists.
This problem helps students practice state, click interaction, selected-item rendering, props, and dynamic styling.
Functional Requirements
Display a list of songs.
Each song should include:
idtitleartist
The first song should be selected by default.
Clicking a song should:
- mark it as selected
- update the details panel
The selected song should be styled differently.
The details panel should show:
- selected song title
- selected song artist
Use a child component to render each song row.
Concepts Covered
- State
- Props
useState- Dynamic rendering
- Conditional styling
- List rendering
Hints
- Store the selected song’s
idin state instead of storing the whole object. - Use
find()to get the selected song data. - Pass
isSelectedas a prop to the child component. - The click handler should update only the selected ID.
- This is a common “master-detail” UI pattern.
Code Stub
import React, { useState } from "react";
const songs = [
{ id: 1, title: "Blinding Lights", artist: "The Weeknd" },
{ id: 2, title: "Levitating", artist: "Dua Lipa" },
{ id: 3, title: "Heat Waves", artist: "Glass Animals" },
];
function SongItem({ song, isSelected, onSelect }) {
return (
<div
onClick={() => onSelect(song.id)}
style={{
padding: "10px",
border: "1px solid #ddd",
marginBottom: "8px",
cursor: "pointer",
}}
>
<strong>{song.title}</strong>
<p>{song.artist}</p>
</div>
);
}
export default function PlaylistHighlighter() {
const [selectedSongId, setSelectedSongId] = useState(1);
// TODO: derive selected song
const selectedSong = songs[0];
return (
<div style={{ padding: "20px" }}>
<h2>Playlist</h2>
<div>
{songs.map((song) => (
<SongItem
key={song.id}
song={song}
isSelected={false}
onSelect={setSelectedSongId}
/>
))}
</div>
<div style={{ marginTop: "20px" }}>
<h3>Now Selected</h3>
<p>Title: {selectedSong.title}</p>
<p>Artist: {selectedSong.artist}</p>
</div>
</div>
);
}Full Solution
import React, { useState } from "react";
const songs = [
{ id: 1, title: "Blinding Lights", artist: "The Weeknd" },
{ id: 2, title: "Levitating", artist: "Dua Lipa" },
{ id: 3, title: "Heat Waves", artist: "Glass Animals" },
];
function SongItem({ song, isSelected, onSelect }) {
return (
<div
onClick={() => onSelect(song.id)}
style={{
padding: "10px",
border: "1px solid #ddd",
marginBottom: "8px",
cursor: "pointer",
backgroundColor: isSelected ? "#e6f0ff" : "white",
}}
>
<strong>{song.title}</strong>
<p>{song.artist}</p>
</div>
);
}
export default function PlaylistHighlighter() {
const [selectedSongId, setSelectedSongId] = useState(1);
const selectedSong = songs.find((song) => song.id === selectedSongId);
return (
<div style={{ padding: "20px" }}>
<h2>Playlist</h2>
<div>
{songs.map((song) => (
<SongItem
key={song.id}
song={song}
isSelected={selectedSongId === song.id}
onSelect={setSelectedSongId}
/>
))}
</div>
<div style={{ marginTop: "20px" }}>
<h3>Now Selected</h3>
<p>Title: {selectedSong.title}</p>
<p>Artist: {selectedSong.artist}</p>
</div>
</div>
);
}Test Cases
Action: App loads Expected: First song is selected by default.
Action: User clicks second song Expected: Second song becomes selected.
Action: User clicks third song Expected: Third song becomes selected.
Action: Selected song changes Expected: Details panel updates to the correct title and artist.
Action: A song is selected Expected: That row is visually highlighted.
Action: User clicks the same song again Expected: It stays selected.
Action: User switches between songs repeatedly Expected: Highlight and details panel always remain synchronized.
Action: Song rows render Expected: Each row shows title and artist.
Action: App first renders Expected: Details panel matches the first song.
Action: User selects another song Expected: Previous song loses highlight.
Problem 3: Job Application Status Board
Problem Statement
You are building a Job Application Status Board for a career portal. Users should be able to view job applications and filter them by their status:
- Applied
- Interview
- Rejected
This kind of feature is commonly seen in job boards, hiring dashboards, and tracking applications. The UI should allow users to switch views and inspect only the subset they need at the moment.
This problem helps students practice filtering, state-driven UI, button-based view switching, and rendering lists of objects.
Functional Requirements
Display a list of job applications.
Each application should include:
idcompanyrolestatus
Add four filter buttons:
- All
- Applied
- Interview
- Rejected
By default, show all applications.
Clicking a filter button should show only matching applications.
Highlight the active filter button.
If no applications match the current filter, show:
No applications found
Show the number of visible applications.
Concepts Covered
- State
useState- Conditional rendering
- List filtering
- Derived UI
Hints
- Store the active filter in state.
- Use
filter()to compute the visible applications. - The
Allfilter is just a special case. - Visible count should come from the filtered array.
- Button styles should depend on active state.
Code Stub
import React, { useState } from "react";
const applications = [
{ id: 1, company: "Google", role: "Frontend Engineer", status: "Applied" },
{ id: 2, company: "Amazon", role: "SDE 1", status: "Interview" },
{ id: 3, company: "Meta", role: "UI Engineer", status: "Rejected" },
{ id: 4, company: "Atlassian", role: "React Developer", status: "Applied" },
];
export default function JobStatusBoard() {
const [activeFilter, setActiveFilter] = useState("All");
// TODO: derive visible applications
const visibleApplications = applications;
return (
<div style={{ padding: "20px" }}>
<h2>Job Application Status Board</h2>
<button onClick={() => setActiveFilter("All")}>All</button>
<button onClick={() => setActiveFilter("Applied")} style={{ marginLeft: "10px" }}>
Applied
</button>
<button onClick={() => setActiveFilter("Interview")} style={{ marginLeft: "10px" }}>
Interview
</button>
<button onClick={() => setActiveFilter("Rejected")} style={{ marginLeft: "10px" }}>
Rejected
</button>
<p style={{ marginTop: "20px" }}>Visible Applications: {visibleApplications.length}</p>
{visibleApplications.map((application) => (
<div key={application.id} style={{ border: "1px solid #ddd", padding: "10px", marginBottom: "10px" }}>
<h4>{application.company}</h4>
<p>{application.role}</p>
<p>Status: {application.status}</p>
</div>
))}
</div>
);
}Full Solution
import React, { useState } from "react";
const applications = [
{ id: 1, company: "Google", role: "Frontend Engineer", status: "Applied" },
{ id: 2, company: "Amazon", role: "SDE 1", status: "Interview" },
{ id: 3, company: "Meta", role: "UI Engineer", status: "Rejected" },
{ id: 4, company: "Atlassian", role: "React Developer", status: "Applied" },
];
export default function JobStatusBoard() {
const [activeFilter, setActiveFilter] = useState("All");
const visibleApplications =
activeFilter === "All"
? applications
: applications.filter((application) => application.status === activeFilter);
const getButtonStyle = (filter) => ({
backgroundColor: activeFilter === filter ? "#ddd" : "white",
padding: "8px 12px",
});
return (
<div style={{ padding: "20px" }}>
<h2>Job Application Status Board</h2>
<button onClick={() => setActiveFilter("All")} style={getButtonStyle("All")}>
All
</button>
<button
onClick={() => setActiveFilter("Applied")}
style={{ ...getButtonStyle("Applied"), marginLeft: "10px" }}
>
Applied
</button>
<button
onClick={() => setActiveFilter("Interview")}
style={{ ...getButtonStyle("Interview"), marginLeft: "10px" }}
>
Interview
</button>
<button
onClick={() => setActiveFilter("Rejected")}
style={{ ...getButtonStyle("Rejected"), marginLeft: "10px" }}
>
Rejected
</button>
<p style={{ marginTop: "20px" }}>
Visible Applications: {visibleApplications.length}
</p>
{visibleApplications.length === 0 ? (
<p>No applications found</p>
) : (
visibleApplications.map((application) => (
<div
key={application.id}
style={{ border: "1px solid #ddd", padding: "10px", marginBottom: "10px", borderRadius: "8px" }}
>
<h4>{application.company}</h4>
<p>{application.role}</p>
<p>Status: {application.status}</p>
</div>
))
)}
</div>
);
}Test Cases
Action: App loads Expected: All applications are visible.
Action: User clicks
AppliedExpected: Only applied jobs are shown.Action: User clicks
InterviewExpected: Only interview jobs are shown.Action: User clicks
RejectedExpected: Only rejected jobs are shown.Action: User clicks
AllExpected: Full application list is visible again.Action: Active filter changes Expected: Correct button is highlighted.
Action: Visible applications are filtered Expected: Count updates to match rendered cards.
Action: No items match a filter Expected:
No applications foundis shown.Action: User switches filters multiple times Expected: UI always remains accurate.
Action: Each application card renders Expected: Company, role, and status are all visible.
Problem 4: Product Image Color Preview
Problem Statement
You are building a Product Color Preview widget for an ecommerce product page. A product is available in multiple color options, and when a user clicks on a color swatch, the product preview should update to show the selected variant.
This kind of interaction is extremely common in ecommerce applications where customers compare visual variants before making a purchase decision.
The purpose of this problem is to help students practice selected state, dynamic rendering, conditional styling, and props-based component design.
Functional Requirements
Show a product title.
Show a main preview image for the selected color variant.
Provide a set of color option buttons.
Each color option should contain:
idcolorNameimage
The first color should be selected by default.
Clicking a color option should:
- update the preview image
- highlight the selected option
Show the selected color name below the image.
Use a child component for the color option item.
Concepts Covered
- State
- Props
useState- Dynamic rendering
- Conditional styling
- Reusable child components
Hints
- Store the selected color ID in state.
- Use
find()to get the selected color object. - Pass selected state into the child swatch component.
- The main image should depend entirely on selected state.
- This is another good example of a master-detail UI.
Code Stub
import React, { useState } from "react";
const colorVariants = [
{ id: 1, colorName: "Black", image: "https://via.placeholder.com/300x200?text=Black+Shoes" },
{ id: 2, colorName: "White", image: "https://via.placeholder.com/300x200?text=White+Shoes" },
{ id: 3, colorName: "Blue", image: "https://via.placeholder.com/300x200?text=Blue+Shoes" },
];
function ColorSwatch({ variant, isSelected, onSelect }) {
return (
<button onClick={() => onSelect(variant.id)} style={{ marginRight: "10px" }}>
{variant.colorName}
</button>
);
}
export default function ProductColorPreview() {
const [selectedColorId, setSelectedColorId] = useState(1);
// TODO: derive selected variant
const selectedVariant = colorVariants[0];
return (
<div style={{ padding: "20px" }}>
<h2>Running Shoes</h2>
<img src={selectedVariant.image} alt={selectedVariant.colorName} />
<p>Selected Color: {selectedVariant.colorName}</p>
<div style={{ marginTop: "10px" }}>
{colorVariants.map((variant) => (
<ColorSwatch
key={variant.id}
variant={variant}
isSelected={false}
onSelect={setSelectedColorId}
/>
))}
</div>
</div>
);
}Full Solution
import React, { useState } from "react";
const colorVariants = [
{ id: 1, colorName: "Black", image: "https://via.placeholder.com/300x200?text=Black+Shoes" },
{ id: 2, colorName: "White", image: "https://via.placeholder.com/300x200?text=White+Shoes" },
{ id: 3, colorName: "Blue", image: "https://via.placeholder.com/300x200?text=Blue+Shoes" },
];
function ColorSwatch({ variant, isSelected, onSelect }) {
return (
<button
onClick={() => onSelect(variant.id)}
style={{
marginRight: "10px",
padding: "8px 12px",
backgroundColor: isSelected ? "#ddd" : "white",
}}
>
{variant.colorName}
</button>
);
}
export default function ProductColorPreview() {
const [selectedColorId, setSelectedColorId] = useState(1);
const selectedVariant = colorVariants.find(
(variant) => variant.id === selectedColorId
);
return (
<div style={{ padding: "20px" }}>
<h2>Running Shoes</h2>
<img
src={selectedVariant.image}
alt={selectedVariant.colorName}
style={{ width: "300px", height: "200px", objectFit: "cover" }}
/>
<p>Selected Color: {selectedVariant.colorName}</p>
<div style={{ marginTop: "10px" }}>
{colorVariants.map((variant) => (
<ColorSwatch
key={variant.id}
variant={variant}
isSelected={selectedColorId === variant.id}
onSelect={setSelectedColorId}
/>
))}
</div>
</div>
);
}Test Cases
Action: App loads Expected: First color variant is selected by default.
Action: User clicks
WhiteExpected: White image is shown.Action: User clicks
BlueExpected: Blue image is shown.Action: User changes color Expected: Selected color name updates correctly.
Action: Selected variant changes Expected: Active swatch is highlighted.
Action: Previous selected color loses focus state Expected: Only one swatch appears selected.
Action: User clicks different swatches repeatedly Expected: Preview image always matches the chosen swatch.
Action: App first renders Expected: Product title, image, and selected color text are visible.
Action: User clicks selected swatch again Expected: It remains selected without errors.
Action: Image alt text is rendered Expected: It matches the selected color name.
Problem 5: Classroom Attendance Toggle List
Problem Statement
You are building a Classroom Attendance Toggle List for a teacher dashboard. The teacher sees a list of students and can mark whether each student is present or absent.
Each student row should have a button that toggles attendance status. The dashboard should also show a live summary of how many students are present and absent.
This is a practical feature for education tools, admin systems, and classroom management software. It gives students practice with updating objects inside arrays, deriving counts, props, and conditional rendering.
Functional Requirements
Display a list of students.
Each student should contain:
idnamepresent
Each student row should show:
- student name
- attendance status
- a toggle button
Clicking the button should switch:
- Present → Absent
- Absent → Present
Present students should look visually different from absent students.
Show summary counts:
- total students
- present students
- absent students
Use a child component for each student row.
Concepts Covered
- State
- Props
useState- List updates
- Derived UI
- Conditional styling
Hints
- Keep the students array in state.
- Use
map()to update just the clicked student. - Present and absent counts should be derived from the state array.
- Pass the toggle handler and student data through props.
- Styling can depend on the
presentboolean.
Code Stub
import React, { useState } from "react";
const initialStudents = [
{ id: 1, name: "Aarav", present: true },
{ id: 2, name: "Meera", present: false },
{ id: 3, name: "Kunal", present: true },
{ id: 4, name: "Ishita", present: false },
];
function StudentRow({ student, onToggle }) {
return (
<div style={{ border: "1px solid #ddd", padding: "10px", marginBottom: "10px" }}>
<h4>{student.name}</h4>
<p>Status: {student.present ? "Present" : "Absent"}</p>
<button onClick={() => onToggle(student.id)}>
{/* TODO */}
</button>
</div>
);
}
export default function AttendanceToggleList() {
const [students, setStudents] = useState(initialStudents);
// TODO: implement toggle logic
const handleToggleAttendance = (id) => {};
const totalStudents = students.length;
const presentCount = 0;
const absentCount = 0;
return (
<div style={{ padding: "20px" }}>
<h2>Attendance Dashboard</h2>
<p>Total Students: {totalStudents}</p>
<p>Present: {presentCount}</p>
<p>Absent: {absentCount}</p>
<div style={{ marginTop: "20px" }}>
{students.map((student) => (
<StudentRow
key={student.id}
student={student}
onToggle={handleToggleAttendance}
/>
))}
</div>
</div>
);
}Full Solution
import React, { useState } from "react";
const initialStudents = [
{ id: 1, name: "Aarav", present: true },
{ id: 2, name: "Meera", present: false },
{ id: 3, name: "Kunal", present: true },
{ id: 4, name: "Ishita", present: false },
];
function StudentRow({ student, onToggle }) {
return (
<div
style={{
border: "1px solid #ddd",
padding: "10px",
marginBottom: "10px",
backgroundColor: student.present ? "#eafbea" : "#fdeaea",
borderRadius: "8px",
}}
>
<h4>{student.name}</h4>
<p>Status: {student.present ? "Present" : "Absent"}</p>
<button onClick={() => onToggle(student.id)}>
{student.present ? "Mark Absent" : "Mark Present"}
</button>
</div>
);
}
export default function AttendanceToggleList() {
const [students, setStudents] = useState(initialStudents);
const handleToggleAttendance = (id) => {
setStudents((prev) =>
prev.map((student) =>
student.id === id
? { ...student, present: !student.present }
: student
)
);
};
const totalStudents = students.length;
const presentCount = students.filter((student) => student.present).length;
const absentCount = totalStudents - presentCount;
return (
<div style={{ padding: "20px" }}>
<h2>Attendance Dashboard</h2>
<p>Total Students: {totalStudents}</p>
<p>Present: {presentCount}</p>
<p>Absent: {absentCount}</p>
<div style={{ marginTop: "20px" }}>
{students.map((student) => (
<StudentRow
key={student.id}
student={student}
onToggle={handleToggleAttendance}
/>
))}
</div>
</div>
);
}Test Cases
Action: App loads Expected: All students are displayed.
Action: App loads Expected: Present and absent counts match the student data.
Action: User clicks
Mark Presenton an absent student Expected: That student becomes present.Action: User clicks
Mark Absenton a present student Expected: That student becomes absent.Action: Student attendance changes Expected: Present/absent summary updates correctly.
Action: Present student row renders Expected: It uses present-specific styling.
Action: Absent student row renders Expected: It uses absent-specific styling.
Action: User toggles the same student twice Expected: Status switches back correctly.
Action: User toggles multiple students Expected: All counts remain accurate.
Action: Each row renders Expected: Student name, status, and correct button text are visible.
Great — here is Set 2 of the 30-question React practice sheet, covering Problems 6–10 in the same detailed format.
This set starts introducing slightly richer interaction patterns, including:
- search-based filtering
- parent-child coordination
- lifting state up
- basic
useEffect - derived summaries
- empty states
- reusable components
Problem 6: Team Directory Search Panel
Problem Statement
You are building a Team Directory Search Panel for an internal company dashboard. Employees should be able to search through a list of team members by name and quickly find the person they are looking for.
This is a very common feature in admin tools, collaboration apps, HR portals, and internal dashboards. The goal is to help students practice controlled inputs, filtering lists, derived UI, and empty-state handling in React.
The interaction should feel realistic: the user types into the search bar, and the visible employee list updates immediately.
Functional Requirements
Display a list of team members.
Each team member should have:
idnamerole
Add a search input at the top.
The search input should be a controlled component.
Filter members by name as the user types.
Matching should be case-insensitive.
Show the total number of visible results.
If no team members match the search, show:
No team members found
Use a child component to render each member card.
Concepts Covered
- State
- Props
useState- Controlled components
- List filtering
- Derived UI
- Conditional rendering
Hints
- Keep the search value in state.
- Use
filter()on the original members array. - Convert both the member name and search text to lowercase before comparing.
- The visible count should come from the filtered array.
- The child component should only focus on display, not filtering logic.
Code Stub
import React, { useState } from "react";
const members = [
{ id: 1, name: "Aarav Sharma", role: "Frontend Engineer" },
{ id: 2, name: "Meera Nair", role: "Product Designer" },
{ id: 3, name: "Kabir Jain", role: "Backend Engineer" },
{ id: 4, name: "Ishita Rao", role: "QA Engineer" },
];
function MemberCard({ member }) {
return (
<div style={{ border: "1px solid #ddd", padding: "10px", marginBottom: "10px" }}>
<h4>{member.name}</h4>
<p>{member.role}</p>
</div>
);
}
export default function TeamDirectorySearch() {
const [search, setSearch] = useState("");
// TODO: derive visible members
const visibleMembers = members;
return (
<div style={{ padding: "20px" }}>
<h2>Team Directory</h2>
<input
type="text"
placeholder="Search team members"
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
<p style={{ marginTop: "15px" }}>Visible Members: {visibleMembers.length}</p>
<div style={{ marginTop: "15px" }}>
{visibleMembers.map((member) => (
<MemberCard key={member.id} member={member} />
))}
</div>
</div>
);
}Full Solution
import React, { useState } from "react";
const members = [
{ id: 1, name: "Aarav Sharma", role: "Frontend Engineer" },
{ id: 2, name: "Meera Nair", role: "Product Designer" },
{ id: 3, name: "Kabir Jain", role: "Backend Engineer" },
{ id: 4, name: "Ishita Rao", role: "QA Engineer" },
];
function MemberCard({ member }) {
return (
<div style={{ border: "1px solid #ddd", padding: "10px", marginBottom: "10px", borderRadius: "8px" }}>
<h4>{member.name}</h4>
<p>{member.role}</p>
</div>
);
}
export default function TeamDirectorySearch() {
const [search, setSearch] = useState("");
const visibleMembers = members.filter((member) =>
member.name.toLowerCase().includes(search.toLowerCase())
);
return (
<div style={{ padding: "20px" }}>
<h2>Team Directory</h2>
<input
type="text"
placeholder="Search team members"
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
<p style={{ marginTop: "15px" }}>Visible Members: {visibleMembers.length}</p>
<div style={{ marginTop: "15px" }}>
{visibleMembers.length === 0 ? (
<p>No team members found</p>
) : (
visibleMembers.map((member) => (
<MemberCard key={member.id} member={member} />
))
)}
</div>
</div>
);
}Test Cases
Action: App loads Expected: All members are displayed.
Action: User types
aaravExpected: Only Aarav Sharma is visible.Action: User types
MEERAExpected: Meera Nair is visible due to case-insensitive matching.Action: User types
raoExpected: Ishita Rao is visible.Action: User clears the search input Expected: Full member list returns.
Action: User types a name that does not exist Expected:
No team members foundis displayed.Action: Search text changes Expected: Visible member count updates immediately.
Action: Search is empty Expected: Visible count matches the total member count.
Action: Each member card renders Expected: Member name and role are visible.
Action: User types partial text like
kaExpected: Matching names containingkaare displayed.
Problem 7: Product Rating Filter Bar
Problem Statement
You are building a Product Rating Filter Bar for an ecommerce review page. Users should be able to filter products based on their star rating so they can quickly focus on the highest-rated or lower-rated items.
For example, a user may want to view only products with 4-star ratings or all products with 5 stars. This kind of filtering is common in marketplaces, food delivery platforms, shopping apps, and review sites.
This problem helps students practice state-driven filtering, buttons as filters, and list rendering with real product-style data.
Functional Requirements
Display a list of products.
Each product should have:
idnamerating
Add filter buttons:
- All
- 5 Stars
- 4 Stars
- 3 Stars
By default, show all products.
Clicking a filter button should show only products with that rating.
Highlight the active filter button.
Show the number of visible products.
If no products match the filter, show:
No products available for this rating
Concepts Covered
- State
useState- List filtering
- Conditional rendering
- Derived UI
- Event handling
Hints
- Store the selected rating filter in state.
Allis just a special filter that returns the full array.- Compare numeric ratings carefully.
- Use filtered array length to show the visible count.
- Button styles should depend on the active filter.
Code Stub
import React, { useState } from "react";
const products = [
{ id: 1, name: "Wireless Earbuds", rating: 5 },
{ id: 2, name: "Laptop Stand", rating: 4 },
{ id: 3, name: "Phone Holder", rating: 3 },
{ id: 4, name: "Bluetooth Speaker", rating: 5 },
];
export default function ProductRatingFilter() {
const [activeFilter, setActiveFilter] = useState("All");
// TODO: derive visible products
const visibleProducts = products;
return (
<div style={{ padding: "20px" }}>
<h2>Product Rating Filter</h2>
<button onClick={() => setActiveFilter("All")}>All</button>
<button onClick={() => setActiveFilter(5)} style={{ marginLeft: "10px" }}>
5 Stars
</button>
<button onClick={() => setActiveFilter(4)} style={{ marginLeft: "10px" }}>
4 Stars
</button>
<button onClick={() => setActiveFilter(3)} style={{ marginLeft: "10px" }}>
3 Stars
</button>
<p style={{ marginTop: "15px" }}>Visible Products: {visibleProducts.length}</p>
{visibleProducts.map((product) => (
<div key={product.id} style={{ border: "1px solid #ddd", padding: "10px", marginBottom: "10px" }}>
<h4>{product.name}</h4>
<p>Rating: {product.rating} Stars</p>
</div>
))}
</div>
);
}Full Solution
import React, { useState } from "react";
const products = [
{ id: 1, name: "Wireless Earbuds", rating: 5 },
{ id: 2, name: "Laptop Stand", rating: 4 },
{ id: 3, name: "Phone Holder", rating: 3 },
{ id: 4, name: "Bluetooth Speaker", rating: 5 },
];
export default function ProductRatingFilter() {
const [activeFilter, setActiveFilter] = useState("All");
const visibleProducts =
activeFilter === "All"
? products
: products.filter((product) => product.rating === activeFilter);
const getButtonStyle = (filterValue) => ({
backgroundColor: activeFilter === filterValue ? "#ddd" : "white",
padding: "8px 12px",
});
return (
<div style={{ padding: "20px" }}>
<h2>Product Rating Filter</h2>
<button onClick={() => setActiveFilter("All")} style={getButtonStyle("All")}>
All
</button>
<button onClick={() => setActiveFilter(5)} style={{ ...getButtonStyle(5), marginLeft: "10px" }}>
5 Stars
</button>
<button onClick={() => setActiveFilter(4)} style={{ ...getButtonStyle(4), marginLeft: "10px" }}>
4 Stars
</button>
<button onClick={() => setActiveFilter(3)} style={{ ...getButtonStyle(3), marginLeft: "10px" }}>
3 Stars
</button>
<p style={{ marginTop: "15px" }}>Visible Products: {visibleProducts.length}</p>
{visibleProducts.length === 0 ? (
<p>No products available for this rating</p>
) : (
visibleProducts.map((product) => (
<div
key={product.id}
style={{ border: "1px solid #ddd", padding: "10px", marginBottom: "10px", borderRadius: "8px" }}
>
<h4>{product.name}</h4>
<p>Rating: {product.rating} Stars</p>
</div>
))
)}
</div>
);
}Test Cases
Action: App loads Expected: All products are displayed.
Action: User clicks
5 StarsExpected: Only 5-star products appear.Action: User clicks
4 StarsExpected: Only 4-star products appear.Action: User clicks
3 StarsExpected: Only 3-star products appear.Action: User clicks
AllExpected: All products appear again.Action: Active filter changes Expected: Correct button is highlighted.
Action: No products exist for a selected rating Expected:
No products available for this ratingis shown.Action: Filter changes Expected: Visible product count updates correctly.
Action: Product card renders Expected: Product name and rating are both visible.
Action: User switches filters repeatedly Expected: UI remains accurate and stable.
Problem 8: Shared Selected Course Viewer
Problem Statement
You are building a Shared Selected Course Viewer for an education platform. On the left side, users should see a list of available courses. On the right side, they should see the details of the currently selected course.
The important part of this problem is that the selected course state should live in the parent component, while both the course list and the course details panel depend on it. This is a classic case of lifting state up.
This pattern is very common in dashboards, admin tools, media apps, CRMs, and learning platforms where multiple sibling components need to stay synchronized based on shared parent state.
Functional Requirements
Show a list of courses in one child component.
Show selected course details in another child component.
Each course should include:
idtitleinstructorduration
The first course should be selected by default.
Clicking a course in the list should update the details panel.
Highlight the selected course in the list.
State for selected course should be stored in the parent component.
The child components should communicate via props only.
Concepts Covered
- State
- Props
useState- Lifting state up
- Parent-child communication
- Dynamic rendering
Hints
- The parent should own
selectedCourseId. - Pass the selected ID and click handler down to the list component.
- Pass the selected course data down to the details component.
- Use
find()in the parent to derive the selected course. - This is a good example of siblings sharing one source of truth.
Code Stub
import React, { useState } from "react";
const courses = [
{ id: 1, title: "React Basics", instructor: "Mrinal", duration: "4 Weeks" },
{ id: 2, title: "Advanced JavaScript", instructor: "Aman", duration: "6 Weeks" },
{ id: 3, title: "Node.js Fundamentals", instructor: "Riya", duration: "5 Weeks" },
];
function CourseList({ courses, selectedCourseId, onSelect }) {
return (
<div>
{courses.map((course) => (
<button
key={course.id}
onClick={() => onSelect(course.id)}
style={{ display: "block", marginBottom: "10px" }}
>
{course.title}
</button>
))}
</div>
);
}
function CourseDetails({ course }) {
return (
<div>
<h3>{course.title}</h3>
<p>Instructor: {course.instructor}</p>
<p>Duration: {course.duration}</p>
</div>
);
}
export default function SharedCourseViewer() {
const [selectedCourseId, setSelectedCourseId] = useState(1);
// TODO: derive selected course
const selectedCourse = courses[0];
return (
<div style={{ padding: "20px" }}>
<h2>Course Viewer</h2>
<div style={{ display: "flex", gap: "20px" }}>
<CourseList
courses={courses}
selectedCourseId={selectedCourseId}
onSelect={setSelectedCourseId}
/>
<CourseDetails course={selectedCourse} />
</div>
</div>
);
}Full Solution
import React, { useState } from "react";
const courses = [
{ id: 1, title: "React Basics", instructor: "Mrinal", duration: "4 Weeks" },
{ id: 2, title: "Advanced JavaScript", instructor: "Aman", duration: "6 Weeks" },
{ id: 3, title: "Node.js Fundamentals", instructor: "Riya", duration: "5 Weeks" },
];
function CourseList({ courses, selectedCourseId, onSelect }) {
return (
<div>
{courses.map((course) => (
<button
key={course.id}
onClick={() => onSelect(course.id)}
style={{
display: "block",
marginBottom: "10px",
backgroundColor: selectedCourseId === course.id ? "#ddd" : "white",
padding: "8px 12px",
}}
>
{course.title}
</button>
))}
</div>
);
}
function CourseDetails({ course }) {
return (
<div style={{ border: "1px solid #ddd", padding: "15px", borderRadius: "8px", minWidth: "250px" }}>
<h3>{course.title}</h3>
<p>Instructor: {course.instructor}</p>
<p>Duration: {course.duration}</p>
</div>
);
}
export default function SharedCourseViewer() {
const [selectedCourseId, setSelectedCourseId] = useState(1);
const selectedCourse = courses.find(
(course) => course.id === selectedCourseId
);
return (
<div style={{ padding: "20px" }}>
<h2>Course Viewer</h2>
<div style={{ display: "flex", gap: "20px" }}>
<CourseList
courses={courses}
selectedCourseId={selectedCourseId}
onSelect={setSelectedCourseId}
/>
<CourseDetails course={selectedCourse} />
</div>
</div>
);
}Test Cases
Action: App loads Expected: First course is selected by default.
Action: User clicks second course Expected: Second course details appear on the right.
Action: User clicks third course Expected: Third course details appear.
Action: Selected course changes Expected: Correct course button is highlighted.
Action: Previous selected course changes Expected: Previous course button loses highlight.
Action: Course details panel renders Expected: Title, instructor, and duration are visible.
Action: State changes in parent Expected: Both child components update consistently.
Action: User switches courses repeatedly Expected: List and details panel remain synchronized.
Action: Course list renders Expected: All course titles appear as selectable buttons.
Action: App first loads Expected: List selection and details panel match each other.
Problem 9: Auto-Updating Welcome Banner
Problem Statement
You are building an Auto-Updating Welcome Banner for a learning dashboard. When the page loads, the banner should first show Loading user.... After 2 seconds, it should automatically update to show a welcome message such as Welcome back, Student!.
This simulates a simple asynchronous loading state that often appears in dashboards, profile screens, and SaaS apps when waiting for user data or remote content.
The purpose of this problem is to introduce students to useEffect for side effects and delayed UI updates.
Functional Requirements
When the component first loads, show:
Loading user...
After 2 seconds, automatically update the banner to:
Welcome back, Student!
Use
useEffectfor the delayed update.Keep the logic in a single component.
The UI should re-render automatically when the message changes.
Concepts Covered
- State
useStateuseEffect- Side effects
- Conditional rendering
Hints
- Use one piece of state for the banner text.
useEffectcan run once after the component mounts.- Use
setTimeout()inside the effect. - Update state after the delay.
- The initial state should represent loading.
Code Stub
import React, { useEffect, useState } from "react";
export default function WelcomeBanner() {
const [message, setMessage] = useState("Loading user...");
// TODO: update message after 2 seconds
useEffect(() => {
}, []);
return (
<div style={{ padding: "20px", border: "1px solid #ddd" }}>
<h2>Dashboard Banner</h2>
<p>{message}</p>
</div>
);
}Full Solution
import React, { useEffect, useState } from "react";
export default function WelcomeBanner() {
const [message, setMessage] = useState("Loading user...");
useEffect(() => {
const timerId = setTimeout(() => {
setMessage("Welcome back, Student!");
}, 2000);
return () => clearTimeout(timerId);
}, []);
return (
<div style={{ padding: "20px", border: "1px solid #ddd", borderRadius: "8px" }}>
<h2>Dashboard Banner</h2>
<p>{message}</p>
</div>
);
}Test Cases
Action: App loads Expected: Banner shows
Loading user...Action: 2 seconds pass Expected: Banner updates to
Welcome back, Student!Action: Before 2 seconds are complete Expected: Banner still shows loading message.
Action: State updates after timeout Expected: Component re-renders with the new message.
Action: Component unmounts before timeout completes Expected: Cleanup prevents unwanted timeout side effects.
Action: App renders first time Expected: Heading and banner text are visible.
Action: Delay completes only once Expected: Message changes once and stays stable.
Action: App remains mounted Expected: Welcome message remains visible after update.
Action:
useEffectruns Expected: It runs only once on initial mount.Action: Timer finishes Expected: UI reflects updated message without manual refresh.
Problem 10: Recently Viewed Articles Tracker
Problem Statement
You are building a Recently Viewed Articles Tracker for a news platform. Users should be able to click article titles from a list and see the last article they viewed displayed in a small summary panel.
This is a realistic feature because news websites, blogs, learning platforms, and content apps often surface the user’s recently selected or last-viewed item. The key learning here is keeping one selected value in state and deriving the summary panel from it.
This problem is intentionally simple, but it builds strong foundational understanding for later “selected item” and “history” based UI patterns.
Functional Requirements
Display a list of article titles.
Each article should contain:
idtitlecategory
By default, the summary panel should say:
No article viewed yet
Clicking an article should update the summary panel with:
- article title
- article category
The selected article row should be highlighted.
Use a child component to render each article item.
Concepts Covered
- State
- Props
useState- Conditional rendering
- Dynamic rendering
- List rendering
Hints
- Store the last viewed article ID in state, starting with
null. - Use
find()to locate the selected article. - Only show the details panel when a valid article exists.
- Pass
isSelectedto the child component for highlighting. - This is very similar to real content selection interfaces.
Code Stub
import React, { useState } from "react";
const articles = [
{ id: 1, title: "React 19 Features", category: "Frontend" },
{ id: 2, title: "Node.js Scaling Tips", category: "Backend" },
{ id: 3, title: "Designing Better APIs", category: "System Design" },
];
function ArticleItem({ article, isSelected, onView }) {
return (
<div
onClick={() => onView(article.id)}
style={{
border: "1px solid #ddd",
padding: "10px",
marginBottom: "10px",
cursor: "pointer",
}}
>
<h4>{article.title}</h4>
<p>{article.category}</p>
</div>
);
}
export default function ViewedArticlesTracker() {
const [viewedArticleId, setViewedArticleId] = useState(null);
// TODO: derive viewedArticle
const viewedArticle = null;
return (
<div style={{ padding: "20px" }}>
<h2>Articles</h2>
<div>
{articles.map((article) => (
<ArticleItem
key={article.id}
article={article}
isSelected={false}
onView={setViewedArticleId}
/>
))}
</div>
<div style={{ marginTop: "20px" }}>
<h3>Recently Viewed</h3>
<p>No article viewed yet</p>
</div>
</div>
);
}Full Solution
import React, { useState } from "react";
const articles = [
{ id: 1, title: "React 19 Features", category: "Frontend" },
{ id: 2, title: "Node.js Scaling Tips", category: "Backend" },
{ id: 3, title: "Designing Better APIs", category: "System Design" },
];
function ArticleItem({ article, isSelected, onView }) {
return (
<div
onClick={() => onView(article.id)}
style={{
border: "1px solid #ddd",
padding: "10px",
marginBottom: "10px",
cursor: "pointer",
backgroundColor: isSelected ? "#eef4ff" : "white",
borderRadius: "8px",
}}
>
<h4>{article.title}</h4>
<p>{article.category}</p>
</div>
);
}
export default function ViewedArticlesTracker() {
const [viewedArticleId, setViewedArticleId] = useState(null);
const viewedArticle = articles.find(
(article) => article.id === viewedArticleId
);
return (
<div style={{ padding: "20px" }}>
<h2>Articles</h2>
<div>
{articles.map((article) => (
<ArticleItem
key={article.id}
article={article}
isSelected={viewedArticleId === article.id}
onView={setViewedArticleId}
/>
))}
</div>
<div style={{ marginTop: "20px", borderTop: "1px solid #ddd", paddingTop: "15px" }}>
<h3>Recently Viewed</h3>
{viewedArticle ? (
<>
<p>Title: {viewedArticle.title}</p>
<p>Category: {viewedArticle.category}</p>
</>
) : (
<p>No article viewed yet</p>
)}
</div>
</div>
);
}Test Cases
Action: App loads Expected: Summary panel shows
No article viewed yet.Action: User clicks first article Expected: Summary shows first article title and category.
Action: User clicks second article Expected: Summary updates to second article details.
Action: User clicks third article Expected: Summary updates to third article details.
Action: An article is clicked Expected: That row becomes highlighted.
Action: User clicks another article Expected: Previous highlight is removed and new one appears.
Action: Before any click Expected: No row is highlighted.
Action: Article list renders Expected: All titles and categories are shown.
Action: User clicks the same article multiple times Expected: Summary remains correct and stable.
Action: Selected article changes Expected: Summary panel and row highlight stay in sync.
Great — here is Set 3 of the 30-question React practice sheet, covering Problems 11–15 in the same detailed structure.
This set introduces a slightly wider range of React ideas, including:
- toggling favorites/bookmarks
- multiple filters working together
useReffor DOM interactionuseEffectwith cleanup- slightly richer component composition
Problem 11: Saved Jobs Bookmark Board
Problem Statement
You are building a Saved Jobs Bookmark Board for a job search platform. Users can browse job cards and bookmark jobs they want to revisit later.
Each job card should show a bookmark button. When the user clicks it, the job should switch between saved and unsaved states. The dashboard should also display how many jobs are currently saved.
This is a realistic feature because almost every job board, ecommerce app, content platform, or marketplace allows users to save items for later review. This problem helps students practice updating objects inside arrays, passing handlers through props, and deriving summary counts.
Functional Requirements
Display a list of job cards.
Each job should include:
idcompanyrolesaved
Each job card should show a button:
Save Jobif not savedRemove Savedif already saved
Clicking the button should toggle the saved state for that job.
Saved jobs should appear visually different.
Show a summary count:
Saved Jobs: X
Use a child component to render each job card.
Concepts Covered
- State
- Props
useState- List updates
- Conditional rendering
- Derived UI
Hints
- Keep the full jobs list in state.
- Use
map()to update only the clicked job. - The saved count can be derived using
filter(). - Pass the job object and toggle handler into the child card component.
- Let the button label depend on the
savedvalue.
Code Stub
import React, { useState } from "react";
const initialJobs = [
{ id: 1, company: "Google", role: "Frontend Engineer", saved: false },
{ id: 2, company: "Amazon", role: "SDE 1", saved: true },
{ id: 3, company: "Notion", role: "Product Engineer", saved: false },
];
function JobCard({ job, onToggleSaved }) {
return (
<div style={{ border: "1px solid #ddd", padding: "12px", marginBottom: "10px" }}>
<h4>{job.company}</h4>
<p>{job.role}</p>
<button onClick={() => onToggleSaved(job.id)}>
{/* TODO */}
</button>
</div>
);
}
export default function SavedJobsBoard() {
const [jobs, setJobs] = useState(initialJobs);
// TODO: implement toggle logic
const handleToggleSaved = (id) => {};
const savedCount = 0;
return (
<div style={{ padding: "20px" }}>
<h2>Saved Jobs</h2>
<p>Saved Jobs: {savedCount}</p>
{jobs.map((job) => (
<JobCard key={job.id} job={job} onToggleSaved={handleToggleSaved} />
))}
</div>
);
}Full Solution
import React, { useState } from "react";
const initialJobs = [
{ id: 1, company: "Google", role: "Frontend Engineer", saved: false },
{ id: 2, company: "Amazon", role: "SDE 1", saved: true },
{ id: 3, company: "Notion", role: "Product Engineer", saved: false },
];
function JobCard({ job, onToggleSaved }) {
return (
<div
style={{
border: "1px solid #ddd",
padding: "12px",
marginBottom: "10px",
borderRadius: "8px",
backgroundColor: job.saved ? "#fff7e6" : "white",
}}
>
<h4>{job.company}</h4>
<p>{job.role}</p>
<button onClick={() => onToggleSaved(job.id)}>
{job.saved ? "Remove Saved" : "Save Job"}
</button>
</div>
);
}
export default function SavedJobsBoard() {
const [jobs, setJobs] = useState(initialJobs);
const handleToggleSaved = (id) => {
setJobs((prev) =>
prev.map((job) =>
job.id === id ? { ...job, saved: !job.saved } : job
)
);
};
const savedCount = jobs.filter((job) => job.saved).length;
return (
<div style={{ padding: "20px" }}>
<h2>Saved Jobs</h2>
<p>Saved Jobs: {savedCount}</p>
{jobs.map((job) => (
<JobCard key={job.id} job={job} onToggleSaved={handleToggleSaved} />
))}
</div>
);
}Test Cases
Action: App loads Expected: All job cards are displayed.
Action: App loads Expected: Saved job count matches the initial data.
Action: User clicks
Save Jobon an unsaved job Expected: That job becomes saved.Action: User clicks
Remove Savedon a saved job Expected: That job becomes unsaved.Action: A job becomes saved Expected: Its card styling changes to show saved state.
Action: User toggles a job Expected: Saved count updates correctly.
Action: User toggles the same job twice Expected: It returns to its original state.
Action: Button label changes Expected: It reflects the new saved status.
Action: User saves multiple jobs Expected: Saved count increases accordingly.
Action: User unsaves all saved jobs Expected: Saved count becomes 0.
Problem 12: Product Catalog Search and Stock Filter
Problem Statement
You are building a Product Catalog Search and Stock Filter for an ecommerce admin panel. The admin should be able to search products by name and also toggle whether they want to see only in-stock products.
This problem introduces the idea of applying multiple filters together. The visible list should depend on both the search text and the stock-only toggle.
This is a very realistic interaction pattern because most dashboards, admin tools, and catalog screens allow users to combine search and filters at the same time.
Functional Requirements
Display a list of products.
Each product should include:
idnamecategoryinStock
Add a search input for product name.
The search input should be a controlled component.
Add a checkbox:
Show in-stock only
The visible product list should update based on:
- current search text
- checkbox status
Matching search should be case-insensitive.
Show visible product count.
If no products match, show:
No matching products found
Concepts Covered
- State
useState- Controlled components
- Multiple filters
- Derived UI
- Conditional rendering
Hints
- Keep search text and stock-only state separate.
- Apply both conditions when deriving the visible list.
- You can first filter by search and then by stock, or do both in one filter callback.
- Use
checkedfor checkbox state. - The visible count should come from the filtered list.
Code Stub
import React, { useState } from "react";
const products = [
{ id: 1, name: "Wireless Mouse", category: "Accessories", inStock: true },
{ id: 2, name: "Mechanical Keyboard", category: "Accessories", inStock: false },
{ id: 3, name: "Laptop Stand", category: "Office", inStock: true },
{ id: 4, name: "USB-C Hub", category: "Electronics", inStock: true },
];
export default function ProductSearchStockFilter() {
const [search, setSearch] = useState("");
const [showInStockOnly, setShowInStockOnly] = useState(false);
// TODO: derive visible products using both filters
const visibleProducts = products;
return (
<div style={{ padding: "20px" }}>
<h2>Product Catalog</h2>
<input
type="text"
placeholder="Search products"
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
<label style={{ display: "block", marginTop: "10px" }}>
<input
type="checkbox"
checked={showInStockOnly}
onChange={(e) => setShowInStockOnly(e.target.checked)}
/>
Show in-stock only
</label>
<p style={{ marginTop: "15px" }}>Visible Products: {visibleProducts.length}</p>
{visibleProducts.map((product) => (
<div key={product.id} style={{ border: "1px solid #ddd", padding: "10px", marginBottom: "10px" }}>
<h4>{product.name}</h4>
<p>{product.category}</p>
<p>{product.inStock ? "In Stock" : "Out of Stock"}</p>
</div>
))}
</div>
);
}Full Solution
import React, { useState } from "react";
const products = [
{ id: 1, name: "Wireless Mouse", category: "Accessories", inStock: true },
{ id: 2, name: "Mechanical Keyboard", category: "Accessories", inStock: false },
{ id: 3, name: "Laptop Stand", category: "Office", inStock: true },
{ id: 4, name: "USB-C Hub", category: "Electronics", inStock: true },
];
export default function ProductSearchStockFilter() {
const [search, setSearch] = useState("");
const [showInStockOnly, setShowInStockOnly] = useState(false);
const visibleProducts = products.filter((product) => {
const matchesSearch = product.name
.toLowerCase()
.includes(search.toLowerCase());
const matchesStock = showInStockOnly ? product.inStock : true;
return matchesSearch && matchesStock;
});
return (
<div style={{ padding: "20px" }}>
<h2>Product Catalog</h2>
<input
type="text"
placeholder="Search products"
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
<label style={{ display: "block", marginTop: "10px" }}>
<input
type="checkbox"
checked={showInStockOnly}
onChange={(e) => setShowInStockOnly(e.target.checked)}
/>
Show in-stock only
</label>
<p style={{ marginTop: "15px" }}>Visible Products: {visibleProducts.length}</p>
{visibleProducts.length === 0 ? (
<p>No matching products found</p>
) : (
visibleProducts.map((product) => (
<div
key={product.id}
style={{ border: "1px solid #ddd", padding: "10px", marginBottom: "10px", borderRadius: "8px" }}
>
<h4>{product.name}</h4>
<p>{product.category}</p>
<p>{product.inStock ? "In Stock" : "Out of Stock"}</p>
</div>
))
)}
</div>
);
}Test Cases
- Action: Ap
