You’ve watched the ReactJS tutorials, read the docs, and maybe even copied a few components. But the moment you face a blank editor — no template, no hints — that confident feeling disappears. That’s exactly where real ReactJS learning begins, and this post is built to turn that fear into unstoppable momentum.
Introducing 100 ReactJS practice problems with solutions — your hands-on roadmap from “I understand React” to “I can build with React.” You’ll start with core React pillars like functional components, JSX, props, and useState, then level up to useEffect, useContext, useReducer, React Router, custom hooks, forms, and API calls with fetch or Axios. Every problem is crafted in plain, simple language so you can tackle the challenge yourself first, then unpack the step-by-step solution and truly grasp the why behind the React pattern.
Why is deliberate practice a game changer? Because React development isn’t just a theory — it’s a muscle. Each exercise you solve hard-wires your understanding of component lifecycle, state management, rendering behavior, and performance optimization. Before you know it, building real-world interfaces with JSX, handling events, and managing data flow becomes second nature. This is the skill set that makes you stand out in React projects, frontend interviews, and as a genuine React developer.
Whether you’re falling in love with modern UI development or actively prepping for a tech interview, these challenges will leave you feeling capable, creative, and deeply prepared. Pick a problem, open your code editor (VS Code is perfect), and feel that incredible “I’m really building React apps!” moment. Your journey to ReactJS mastery is just one exercise away.
Try it: 100 Javascript practice problems with solutions
1. Create a functional component that returns “Hello, React!” inside a div.
jsx
function Greeting() {
return <div>Hello, React!</div>;
}
export default Greeting;
2. Use JSX to display your name and age in a paragraph.
jsx
function Info() {
const name = "John";
const age = 30;
return <p>Name: {name}, Age: {age}</p>;
}
export default Info;
3. Write a component that receives name as a prop and displays “Welcome, [name]!”
jsx
function Welcome(props) {
return <div>Welcome, {props.name}!</div>;
}
export default Welcome;
4. Create a component with a button that logs “Clicked!” to the console when pressed.
jsx
function ClickLogger() {
const handleClick = () => console.log("Clicked!");
return <button onClick={handleClick}>Click me</button>;
}
export default ClickLogger;
5. Use useState to create a counter that increments when a button is clicked.
jsx
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
export default Counter;
6. Build a toggle component that shows/hides a paragraph using a button (useState).
jsx
import { useState } from "react";
function Toggle() {
const [visible, setVisible] = useState(false);
return (
<div>
<button onClick={() => setVisible(!visible)}>
{visible ? "Hide" : "Show"}
</button>
{visible && <p>This paragraph can be toggled!</p>}
</div>
);
}
export default Toggle;
7. Create a list component that renders an array of fruits using map().
jsx
function FruitList() {
const fruits = ["Apple", "Banana", "Cherry"];
return (
<ul>
{fruits.map((fruit, index) => (
<li key={index}>{fruit}</li>
))}
</ul>
);
}
export default FruitList;
8. Use useEffect to log a message when the component mounts.
jsx
import { useEffect } from "react";
function MountLogger() {
useEffect(() => {
console.log("Component mounted");
}, []);
return <div>Check console</div>;
}
export default MountLogger;
9. Build a component that fetches data from https://jsonplaceholder.typicode.com/posts/1 and displays the title.
jsx
import { useState, useEffect } from "react";
function FetchData() {
const [title, setTitle] = useState("");
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then((res) => res.json())
.then((data) => setTitle(data.title));
}, []);
return <div>Post title: {title}</div>;
}
export default FetchData;
10. Create a controlled input component that displays the typed text live.
jsx
import { useState } from "react";
function LiveInput() {
const [text, setText] = useState("");
return (
<div>
<input
type="text"
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="Type something"
/>
<p>You typed: {text}</p>
</div>
);
}
export default LiveInput;
11. Pass a callback from parent to child to update parent state (lift state up).
jsx
import { useState } from "react";
function Child({ onButtonClick }) {
return <button onClick={onButtonClick}>Click Child</button>;
}
function Parent() {
const [message, setMessage] = useState("");
const handleClick = () => setMessage("Button clicked in child!");
return (
<div>
<Child onButtonClick={handleClick} />
<p>{message}</p>
</div>
);
}
export default Parent;
Also try it: 100 jquery practice problems with solutions
12. Use conditional rendering to display “Loading…” while data is being fetched.
jsx
import { useState, useEffect } from "react";
function LoadingExample() {
const [loading, setLoading] = useState(true);
const [data, setData] = useState(null);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((res) => res.json())
.then((json) => {
setData(json);
setLoading(false);
});
}, []);
if (loading) return <div>Loading...</div>;
return <div>{data.title}</div>;
}
export default LoadingExample;
13. Create a component that uses useRef to focus an input when a button is clicked.
jsx
import { useRef } from "react";
function FocusInput() {
const inputRef = useRef(null);
const focusInput = () => inputRef.current.focus();
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={focusInput}>Focus Input</button>
</div>
);
}
export default FocusInput;
14. Use useReducer to build a counter with increment and decrement actions.
jsx
import { useReducer } from "react";
const reducer = (state, action) => {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
default:
return state;
}
};
function CounterWithReducer() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: "increment" })}>+</button>
<button onClick={() => dispatch({ type: "decrement" })}>-</button>
</div>
);
}
export default CounterWithReducer;
15. Create a simple useContext example: a theme context that toggles between light and dark.
jsx
import { createContext, useContext, useState } from "react";
const ThemeContext = createContext();
function ThemeProvider({ children }) {
const [theme, setTheme] = useState("light");
const toggleTheme = () =>
setTheme((prev) => (prev === "light" ? "dark" : "light"));
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
function ThemedComponent() {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<div style={{ background: theme === "light" ? "#fff" : "#333", color: theme === "light" ? "#000" : "#fff" }}>
<p>Current theme: {theme}</p>
<button onClick={toggleTheme}>Toggle Theme</button>
</div>
);
}
export default function App() {
return (
<ThemeProvider>
<ThemedComponent />
</ThemeProvider>
);
}
16. Use useMemo to memoize a computed value (e.g., factorial of a number).
jsx
import { useState, useMemo } from "react";
function factorial(n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
function MemoExample() {
const [num, setNum] = useState(5);
const fact = useMemo(() => factorial(num), [num]);
return (
<div>
<input
type="number"
value={num}
onChange={(e) => setNum(parseInt(e.target.value) || 0)}
/>
<p>Factorial of {num} is {fact}</p>
</div>
);
}
export default MemoExample;
17. Use useCallback to prevent unnecessary re‑renders of a child component.
jsx
import { useState, useCallback } from "react";
const Child = React.memo(({ onClick }) => {
console.log("Child rendered");
return <button onClick={onClick}>Click me</button>;
});
function ParentWithCallback() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
console.log("Button clicked");
}, []);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment parent</button>
<Child onClick={handleClick} />
</div>
);
}
export default ParentWithCallback;
18. Create a custom hook useLocalStorage to store a value in localStorage.
jsx
import { useState } from "react";
function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
return initialValue;
}
});
const setValue = (value) => {
try {
const valueToStore =
value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
console.log(error);
}
};
return [storedValue, setValue];
}
// Usage
function LocalStorageComponent() {
const [name, setName] = useLocalStorage("name", "");
return (
<div>
<input value={name} onChange={(e) => setName(e.target.value)} />
<p>Stored name: {name}</p>
</div>
);
}
export default LocalStorageComponent;
19. Build a simple form with multiple fields and display the submitted data on submit.
jsx
import { useState } from "react";
function SimpleForm() {
const [formData, setFormData] = useState({ name: "", email: "" });
const [submitted, setSubmitted] = useState(null);
const handleChange = (e) => {
setFormData({ ...formData, [e.target.name]: e.target.value });
};
const handleSubmit = (e) => {
e.preventDefault();
setSubmitted(formData);
};
return (
<div>
<form onSubmit={handleSubmit}>
<input name="name" placeholder="Name" onChange={handleChange} />
<input name="email" placeholder="Email" onChange={handleChange} />
<button type="submit">Submit</button>
</form>
{submitted && (
<div>
<h3>Submitted:</h3>
<p>Name: {submitted.name}</p>
<p>Email: {submitted.email}</p>
</div>
)}
</div>
);
}
export default SimpleForm;
20. Use React.memo to prevent re‑rendering of a component when props haven’t changed.
jsx
import { useState } from "react";
const ExpensiveChild = React.memo(({ value }) => {
console.log("ExpensiveChild rendered");
return <div>Value: {value}</div>;
});
function ParentMemo() {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount(count + 1)}>Increment parent ({count})</button>
<ExpensiveChild value={42} />
</div>
);
}
export default ParentMemo;
21. Create a component that displays a list of items and allows deleting an item.
jsx
import { useState } from "react";
function DeleteItemList() {
const [items, setItems] = useState(["Apple", "Banana", "Cherry"]);
const deleteItem = (index) => {
setItems(items.filter((_, i) => i !== index));
};
return (
<ul>
{items.map((item, i) => (
<li key={i}>
{item} <button onClick={() => deleteItem(i)}>Delete</button>
</li>
))}
</ul>
);
}
export default DeleteItemList;
22. Use useEffect to set up an interval that increments a counter every second.
jsx
import { useState, useEffect } from "react";
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => setSeconds((s) => s + 1), 1000);
return () => clearInterval(interval);
}, []);
return <div>Seconds: {seconds}</div>;
}
export default Timer;
Also try it: 100 HTML practice problems with solutions
23. Implement a component that fetches data and allows refetching with a button.
jsx
import { useState, useEffect } from "react";
function RefetchButton() {
const [data, setData] = useState(null);
const fetchData = () => {
fetch("https://api.chucknorris.io/jokes/random")
.then((res) => res.json())
.then((json) => setData(json.value));
};
useEffect(() => {
fetchData();
}, []);
return (
<div>
<p>{data}</p>
<button onClick={fetchData}>New Joke</button>
</div>
);
}
export default RefetchButton;
24. Use useLayoutEffect to measure a DOM element’s size after render.
jsx
import { useLayoutEffect, useRef, useState } from "react";
function MeasureElement() {
const divRef = useRef();
const [width, setWidth] = useState(0);
useLayoutEffect(() => {
setWidth(divRef.current.offsetWidth);
}, []);
return (
<div>
<div ref={divRef} style={{ width: "50%", background: "lightblue" }}>
Resize me!
</div>
<p>Width: {width}px</p>
</div>
);
}
export default MeasureElement;
25. Build a component that uses React.Children to iterate over children and add a class.
jsx
function AddClassToChildren({ children }) {
return (
<div>
{React.Children.map(children, (child) =>
React.cloneElement(child, { className: "custom-class" })
)}
</div>
);
}
function ChildComponent() {
return <p>I will have a custom class</p>;
}
function ParentExample() {
return (
<AddClassToChildren>
<ChildComponent />
<span>Another child</span>
</AddClassToChildren>
);
}
export default ParentExample;
26. Create a component that uses dangerouslySetInnerHTML to render HTML string.
jsx
function RenderHTML() {
const htmlString = "<strong>Bold text</strong> and <em>italic</em>";
return <div dangerouslySetInnerHTML={{ __html: htmlString }} />;
}
export default RenderHTML;
27. Use React.PureComponent (class component) to avoid unnecessary updates.
jsx
import React from "react";
class PureChild extends React.PureComponent {
render() {
console.log("PureChild rendered");
return <div>{this.props.value}</div>;
}
}
function ParentPure() {
const [count, setCount] = React.useState(0);
return (
<div>
<button onClick={() => setCount(count + 1)}>Increment: {count}</button>
<PureChild value={42} />
</div>
);
}
export default ParentPure;
28. Build a simple modal component that opens/closes using state.
jsx
import { useState } from "react";
function Modal({ isOpen, onClose, children }) {
if (!isOpen) return null;
return (
<div style={{ position: "fixed", top: 0, left: 0, right: 0, bottom: 0, background: "rgba(0,0,0,0.5)", display: "flex", alignItems: "center", justifyContent: "center" }}>
<div style={{ background: "white", padding: 20 }}>
{children}
<button onClick={onClose}>Close</button>
</div>
</div>
);
}
function ModalDemo() {
const [open, setOpen] = useState(false);
return (
<div>
<button onClick={() => setOpen(true)}>Open Modal</button>
<Modal isOpen={open} onClose={() => setOpen(false)}>
<p>This is a modal content!</p>
</Modal>
</div>
);
}
export default ModalDemo;
29. Use useReducer with complex state (e.g., todo list with add/remove).
jsx
import { useReducer } from "react";
const todoReducer = (state, action) => {
switch (action.type) {
case "add":
return [...state, { id: Date.now(), text: action.text }];
case "remove":
return state.filter((todo) => todo.id !== action.id);
default:
return state;
}
};
function TodoList() {
const [todos, dispatch] = useReducer(todoReducer, []);
const [input, setInput] = useState("");
const addTodo = () => {
if (input.trim()) {
dispatch({ type: "add", text: input });
setInput("");
}
};
return (
<div>
<input value={input} onChange={(e) => setInput(e.target.value)} />
<button onClick={addTodo}>Add</button>
<ul>
{todos.map((todo) => (
<li key={todo.id}>
{todo.text}{" "}
<button onClick={() => dispatch({ type: "remove", id: todo.id })}>
Delete
</button>
</li>
))}
</ul>
</div>
);
}
export default TodoList;
30. Create a component that uses React.forwardRef to forward a ref to a button.
jsx
import { useRef } from "react";
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} style={{ background: "pink", padding: 10 }} {...props}>
{props.children}
</button>
));
function ForwardRefDemo() {
const buttonRef = useRef();
const focusButton = () => buttonRef.current.focus();
return (
<div>
<FancyButton ref={buttonRef}>Clickable</FancyButton>
<button onClick={focusButton}>Focus the fancy button</button>
</div>
);
}
export default ForwardRefDemo;
31. Use useImperativeHandle to expose a custom method from a child component.
jsx
import { useRef, useImperativeHandle, forwardRef } from "react";
const Child = forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
alertMessage: () => alert("Hello from child!"),
}));
return <div>Child Component</div>;
});
function ImperativeParent() {
const childRef = useRef();
return (
<div>
<Child ref={childRef} />
<button onClick={() => childRef.current.alertMessage()}>
Call child method
</button>
</div>
);
}
export default ImperativeParent;
32. Create a component that conditionally applies inline styles based on state.
jsx
import { useState } from "react";
function DynamicStyle() {
const [isActive, setIsActive] = useState(false);
const styles = {
backgroundColor: isActive ? "green" : "red",
padding: "10px",
color: "white",
};
return (
<div>
<div style={styles}>This box changes color</div>
<button onClick={() => setIsActive(!isActive)}>Toggle</button>
</div>
);
}
export default DynamicStyle;
33. Use React.StrictMode to wrap root component and identify potential problems.
jsx
import React from "react";
import ReactDOM from "react-dom";
function App() {
return <div>StrictMode enabled</div>;
}
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);
// Note: This is a setup example; not a component itself.
34. Implement a simple pagination component that displays items per page.
jsx
import { useState } from "react";
function Pagination({ items, itemsPerPage }) {
const [currentPage, setCurrentPage] = useState(1);
const totalPages = Math.ceil(items.length / itemsPerPage);
const startIndex = (currentPage - 1) * itemsPerPage;
const currentItems = items.slice(startIndex, startIndex + itemsPerPage);
return (
<div>
<ul>
{currentItems.map((item, i) => (
<li key={i}>{item}</li>
))}
</ul>
<div>
<button disabled={currentPage === 1} onClick={() => setCurrentPage(p => p - 1)}>Prev</button>
<span>Page {currentPage} of {totalPages}</span>
<button disabled={currentPage === totalPages} onClick={() => setCurrentPage(p => p + 1)}>Next</button>
</div>
</div>
);
}
export default function PaginationDemo() {
const data = Array.from({ length: 50 }, (_, i) => `Item ${i + 1}`);
return <Pagination items={data} itemsPerPage={5} />;
}
35. Build a search filter component that filters a list based on input.
jsx
import { useState } from "react";
function SearchFilter() {
const items = ["Apple", "Banana", "Cherry", "Date", "Elderberry"];
const [query, setQuery] = useState("");
const filtered = items.filter(item => item.toLowerCase().includes(query.toLowerCase()));
return (
<div>
<input type="text" placeholder="Search..." value={query} onChange={(e) => setQuery(e.target.value)} />
<ul>
{filtered.map((item, i) => <li key={i}>{item}</li>)}
</ul>
</div>
);
}
export default SearchFilter;
36. Use React.lazy and Suspense to lazy load a component.
jsx
import React, { Suspense } from "react";
const LazyComponent = React.lazy(() => import("./LazyComponent"));
function LazyLoadingExample() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}
export default LazyLoadingExample;
37. Create a component that uses React.createPortal to render a tooltip outside the parent DOM hierarchy.
jsx
import { useState } from "react";
import ReactDOM from "react-dom";
function Tooltip({ children, text }) {
const [isVisible, setIsVisible] = useState(false);
const [coords, setCoords] = useState({ top: 0, left: 0 });
const showTooltip = (e) => {
const rect = e.currentTarget.getBoundingClientRect();
setCoords({ top: rect.bottom, left: rect.left });
setIsVisible(true);
};
const hideTooltip = () => setIsVisible(false);
return (
<div onMouseEnter={showTooltip} onMouseLeave={hideTooltip} style={{ display: "inline-block" }}>
{children}
{isVisible &&
ReactDOM.createPortal(
<div style={{ position: "absolute", top: coords.top, left: coords.left, background: "black", color: "white", padding: "5px", borderRadius: "4px" }}>
{text}
</div>,
document.body
)}
</div>
);
}
function TooltipDemo() {
return (
<Tooltip text="Tooltip content">
<button>Hover me</button>
</Tooltip>
);
}
export default TooltipDemo;
38. Use useDebugValue to label a custom hook.
jsx
import { useState, useDebugValue } from "react";
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
useDebugValue(isOnline ? "Online" : "Offline");
return isOnline;
}
function FriendStatusComponent() {
const status = useFriendStatus(1);
return <div>Friend status: {status === null ? "Unknown" : status ? "Online" : "Offline"}</div>;
}
export default FriendStatusComponent;
39. Create a component that uses React.memo with a custom comparison function.
jsx
import { useState } from "react";
const MemoChild = React.memo(
({ value }) => {
console.log("MemoChild rendered");
return <div>Value: {value}</div>;
},
(prevProps, nextProps) => prevProps.value === nextProps.value
);
function CustomMemoParent() {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount(count + 1)}>Rerender parent ({count})</button>
<MemoChild value={5} />
</div>
);
}
export default CustomMemoParent;
40. Build a component that displays a list of posts from an API with loading and error states.
jsx
import { useState, useEffect } from "react";
function PostList() {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/posts")
.then((res) => {
if (!res.ok) throw new Error("Network response was not ok");
return res.json();
})
.then((data) => {
setPosts(data);
setLoading(false);
})
.catch((err) => {
setError(err.message);
setLoading(false);
});
}, []);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return (
<ul>
{posts.slice(0, 5).map((post) => (
<li key={post.id}>
<strong>{post.title}</strong>
<p>{post.body}</p>
</li>
))}
</ul>
);
}
export default PostList;
41. Create a component that uses useId (React 18) to generate a unique ID for an input.
jsx
import { useId } from "react";
function UniqueIdInput() {
const id = useId();
return (
<div>
<label htmlFor={id}>Name:</label>
<input id={id} type="text" />
</div>
);
}
export default UniqueIdInput;
42. Use useTransition to mark a state update as non‑urgent (React 18).
jsx
import { useState, useTransition } from "react";
function TransitionDemo() {
const [isPending, startTransition] = useTransition();
const [count, setCount] = useState(0);
const handleClick = () => {
startTransition(() => {
setCount(c => c + 1);
});
};
return (
<div>
<button onClick={handleClick}>Increment</button>
{isPending && <div>Pending...</div>}
<div>Count: {count}</div>
</div>
);
}
export default TransitionDemo;
43. Build a component that renders a list of items with an “Add Item” button using an immutable update pattern.
jsx
import { useState } from "react";
function ImmutableList() {
const [items, setItems] = useState(["Item 1"]);
const addItem = () => {
setItems(prev => [...prev, `Item ${prev.length + 1}`]);
};
return (
<div>
<button onClick={addItem}>Add Item</button>
<ul>
{items.map((item, i) => <li key={i}>{item}</li>)}
</ul>
</div>
);
}
export default ImmutableList;
44. Use useSyncExternalStore to subscribe to an external store (e.g., browser’s online status).
jsx
import { useSyncExternalStore } from "react";
function subscribe(callback) {
window.addEventListener("online", callback);
window.addEventListener("offline", callback);
return () => {
window.removeEventListener("online", callback);
window.removeEventListener("offline", callback);
};
}
function getSnapshot() {
return navigator.onLine;
}
function OnlineStatus() {
const isOnline = useSyncExternalStore(subscribe, getSnapshot);
return <div>You are {isOnline ? "online" : "offline"}</div>;
}
export default OnlineStatus;
45. Create a component that uses React.Children.toArray to reorder children.
jsx
function ReorderChildren({ children }) {
const childrenArray = React.Children.toArray(children);
const reversed = [...childrenArray].reverse();
return <div>{reversed}</div>;
}
function ReorderDemo() {
return (
<ReorderChildren>
<div>First</div>
<div>Second</div>
<div>Third</div>
</ReorderChildren>
);
}
export default ReorderDemo;
46. Build a simple form with validation (email and required) and show error messages.
jsx
import { useState } from "react";
function ValidatedForm() {
const [email, setEmail] = useState("");
const [error, setError] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
if (!email.includes("@")) setError("Invalid email address");
else setError("");
};
return (
<form onSubmit={handleSubmit}>
<input type="email" value={email} onChange={(e) => setEmail(e.target.value)} />
{error && <p style={{ color: "red" }}>{error}</p>}
<button type="submit">Submit</button>
</form>
);
}
export default ValidatedForm;
47. Use React.cloneElement to add extra props to children.
jsx
function ExtraProps({ children }) {
return React.Children.map(children, (child) =>
React.cloneElement(child, { extra: "prop" })
);
}
function ChildComponent({ extra }) {
return <div>Received extra: {extra}</div>;
}
function CloneDemo() {
return (
<ExtraProps>
<ChildComponent />
</ExtraProps>
);
}
export default CloneDemo;
48. Implement a component that uses useReducer with context for global state (simple counter).
jsx
import { createContext, useContext, useReducer } from "react";
const CounterContext = createContext();
const counterReducer = (state, action) => {
switch (action.type) {
case "inc": return { count: state.count + 1 };
case "dec": return { count: state.count - 1 };
default: return state;
}
};
function CounterProvider({ children }) {
const [state, dispatch] = useReducer(counterReducer, { count: 0 });
return (
<CounterContext.Provider value={{ state, dispatch }}>
{children}
</CounterContext.Provider>
);
}
function CounterDisplay() {
const { state } = useContext(CounterContext);
return <div>Count: {state.count}</div>;
}
function CounterButtons() {
const { dispatch } = useContext(CounterContext);
return (
<div>
<button onClick={() => dispatch({ type: "inc" })}>+</button>
<button onClick={() => dispatch({ type: "dec" })}>-</button>
</div>
);
}
function GlobalCounter() {
return (
<CounterProvider>
<CounterDisplay />
<CounterButtons />
</CounterProvider>
);
}
export default GlobalCounter;
49. Use React.Profiler to measure rendering performance.
jsx
import { Profiler } from "react";
function onRenderCallback(id, phase, actualDuration) {
console.log(`${id} ${phase} took ${actualDuration}ms`);
}
function ExpensiveComponent() {
// Simulate expensive render
Array.from({ length: 1000 }).forEach(() => {});
return <div>Expensive content</div>;
}
function ProfilerDemo() {
return (
<Profiler id="ExpensiveComponent" onRender={onRenderCallback}>
<ExpensiveComponent />
</Profiler>
);
}
export default ProfilerDemo;
50. Build a component that uses useEffect with cleanup (e.g., remove event listener).
jsx
import { useState, useEffect } from "react";
function MouseTracker() {
const [position, setPosition] = useState({ x: 0, y: 0 });
useEffect(() => {
const handleMove = (e) => setPosition({ x: e.clientX, y: e.clientY });
window.addEventListener("mousemove", handleMove);
return () => window.removeEventListener("mousemove", handleMove);
}, []);
return (
<div>
Mouse position: ({position.x}, {position.y})
</div>
);
}
export default MouseTracker;
51. Use ReactDOM.createRoot and hydrateRoot (concurrent features – for SSR).
jsx
// In index.js (not a component, but a demonstration)
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
// For hydration: ReactDOM.hydrateRoot(document.getElementById("root"), <App />)
52. Create a component that uses useErrorBoundary (React 19 feature) to catch errors.
jsx
// React 19 error boundary hook (concept)
// import { useErrorBoundary } from 'react';
// Not stable yet; use class component error boundary instead.
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError() {
return { hasError: true };
}
render() {
if (this.state.hasError) return <h2>Something went wrong.</h2>;
return this.props.children;
}
}
function BuggyComponent() {
throw new Error("Intentional crash");
return <div>Never rendered</div>;
}
function ErrorBoundaryDemo() {
return (
<ErrorBoundary>
<BuggyComponent />
</ErrorBoundary>
);
}
export default ErrorBoundaryDemo;
Also try it: D3.js practice problems with solutions
53. Build a component that renders a textarea and shows remaining character count.
jsx
import { useState } from "react";
function CharCounter() {
const [text, setText] = useState("");
const max = 100;
const remaining = max - text.length;
return (
<div>
<textarea value={text} onChange={(e) => setText(e.target.value)} maxLength={max} rows={4} cols={50} />
<p>{remaining} characters remaining</p>
</div>
);
}
export default CharCounter;
54. Use React.forwardRef to combine with useImperativeHandle for controlling media playback.
jsx
import { useRef, useImperativeHandle, forwardRef } from "react";
const VideoPlayer = forwardRef(({ src }, ref) => {
const videoRef = useRef();
useImperativeHandle(ref, () => ({
play: () => videoRef.current.play(),
pause: () => videoRef.current.pause(),
}));
return <video ref={videoRef} src={src} width="300" controls />;
});
function MediaControl() {
const playerRef = useRef();
return (
<div>
<VideoPlayer ref={playerRef} src="https://www.w3schools.com/html/mov_bbb.mp4" />
<button onClick={() => playerRef.current.play()}>Play</button>
<button onClick={() => playerRef.current.pause()}>Pause</button>
</div>
);
}
export default MediaControl;
55. Create a component that renders a list of items and allows reordering with drag and drop (using react-beautiful-dnd).
jsx
// Example using react-beautiful-dnd (simplified)
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
import { useState } from "react";
function ReorderList() {
const [items, setItems] = useState(["Item 1", "Item 2", "Item 3"]);
const onDragEnd = (result) => {
if (!result.destination) return;
const reordered = Array.from(items);
const [removed] = reordered.splice(result.source.index, 1);
reordered.splice(result.destination.index, 0, removed);
setItems(reordered);
};
return (
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="droppable">
{(provided) => (
<div ref={provided.innerRef} {...provided.droppableProps}>
{items.map((item, index) => (
<Draggable key={item} draggableId={item} index={index}>
{(provided) => (
<div ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
{item}
</div>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
);
}
export default ReorderList;
56. Use React.memo with a component that receives an object prop to prevent unnecessary renders.
jsx
import { useState, memo } from "react";
const DeepChild = memo(({ data }) => {
console.log("DeepChild rendered");
return <div>{data.name}</div>;
});
function ParentWithObject() {
const [count, setCount] = useState(0);
const obj = { name: "John" }; // new object each time, breaks memo (fixed with useMemo)
return (
<div>
<button onClick={() => setCount(count + 1)}>Increment: {count}</button>
<DeepChild data={obj} />
</div>
);
}
export default ParentWithObject;
57. Fix the above memoization by using useMemo to keep object reference stable.
jsx
import { useState, useMemo } from "react";
const MemoizedChild = React.memo(({ data }) => {
console.log("MemoizedChild rendered");
return <div>{data.name}</div>;
});
function FixedParent() {
const [count, setCount] = useState(0);
const obj = useMemo(() => ({ name: "John" }), []);
return (
<div>
<button onClick={() => setCount(count + 1)}>Increment: {count}</button>
<MemoizedChild data={obj} />
</div>
);
}
export default FixedParent;
58. Create a component that uses useReducer with useContext for a todo app.
jsx
import { createContext, useContext, useReducer } from "react";
const TodoContext = createContext();
const todoReducer = (state, action) => {
switch (action.type) {
case "add": return [...state, { id: Date.now(), text: action.text, done: false }];
case "toggle": return state.map(todo => todo.id === action.id ? { ...todo, done: !todo.done } : todo);
case "delete": return state.filter(todo => todo.id !== action.id);
default: return state;
}
};
function TodoProvider({ children }) {
const [todos, dispatch] = useReducer(todoReducer, []);
return <TodoContext.Provider value={{ todos, dispatch }}>{children}</TodoContext.Provider>;
}
function TodoListComponent() {
const { todos, dispatch } = useContext(TodoContext);
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>
<span style={{ textDecoration: todo.done ? "line-through" : "none" }}>{todo.text}</span>
<button onClick={() => dispatch({ type: "toggle", id: todo.id })}>Toggle</button>
<button onClick={() => dispatch({ type: "delete", id: todo.id })}>Delete</button>
</li>
))}
</ul>
);
}
function AddTodo() {
const { dispatch } = useContext(TodoContext);
const [input, setInput] = useState("");
const add = () => {
if (input.trim()) {
dispatch({ type: "add", text: input });
setInput("");
}
};
return (
<div>
<input value={input} onChange={(e) => setInput(e.target.value)} />
<button onClick={add}>Add</button>
</div>
);
}
function TodoApp() {
return (
<TodoProvider>
<AddTodo />
<TodoListComponent />
</TodoProvider>
);
}
export default TodoApp;
59. Build a component that uses useEffect to fetch data with a cleanup function (abort controller).
jsx
import { useState, useEffect } from "react";
function AbortFetch() {
const [data, setData] = useState(null);
useEffect(() => {
const controller = new AbortController();
const signal = controller.signal;
fetch("https://jsonplaceholder.typicode.com/todos/1", { signal })
.then(res => res.json())
.then(json => setData(json))
.catch(err => {
if (err.name !== "AbortError") console.error(err);
});
return () => controller.abort();
}, []);
return <div>{data && data.title}</div>;
}
export default AbortFetch;
60. Use React.Children.map to count number of children.
jsx
function ChildCounter({ children }) {
const count = React.Children.count(children);
return <div>Number of children: {count}</div>;
}
function CountDemo() {
return (
<ChildCounter>
<p>One</p>
<p>Two</p>
{false && <p>Three</p>}
</ChildCounter>
);
}
export default CountDemo;
61. Create a component that implements an accordion (collapsible section).
jsx
import { useState } from "react";
function Accordion({ title, children }) {
const [isOpen, setIsOpen] = useState(false);
return (
<div style={{ border: "1px solid #ccc", marginBottom: "8px" }}>
<button onClick={() => setIsOpen(!isOpen)} style={{ width: "100%", textAlign: "left", padding: "8px" }}>
{title}
</button>
{isOpen && <div style={{ padding: "8px" }}>{children}</div>}
</div>
);
}
function AccordionDemo() {
return (
<div>
<Accordion title="Section 1">Content for section 1</Accordion>
<Accordion title="Section 2">Content for section 2</Accordion>
</div>
);
}
export default AccordionDemo;
62. Use React.createElement instead of JSX to create a simple component.
jsx
function WithoutJSX() {
return React.createElement(
"div",
{ className: "greeting" },
React.createElement("h1", null, "Hello without JSX"),
React.createElement("p", null, "Using React.createElement")
);
}
export default WithoutJSX;
63. Build a component that renders a form with radio buttons and displays selected value.
jsx
import { useState } from "react";
function RadioGroup() {
const [selected, setSelected] = useState("option1");
return (
<div>
<label>
<input type="radio" value="option1" checked={selected === "option1"} onChange={(e) => setSelected(e.target.value)} />
Option 1
</label>
<label>
<input type="radio" value="option2" checked={selected === "option2"} onChange={(e) => setSelected(e.target.value)} />
Option 2
</label>
<p>Selected: {selected}</p>
</div>
);
}
export default RadioGroup;
64. Create a component that uses useRef to store a mutable value (previous value).
jsx
import { useState, useRef, useEffect } from "react";
function PreviousValue() {
const [count, setCount] = useState(0);
const prevCount = useRef();
useEffect(() => {
prevCount.current = count;
}, [count]);
return (
<div>
<p>Current: {count}</p>
<p>Previous: {prevCount.current}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
export default PreviousValue;
65. Use React.lazy with named exports (component from module).
jsx
// Assume AnotherComponent.js exports default
const AnotherComponent = React.lazy(() => import("./AnotherComponent"));
function LazyNamedDemo() {
return (
<Suspense fallback={<div>Loading...</div>}>
<AnotherComponent />
</Suspense>
);
}
export default LazyNamedDemo;
66. Build a component that uses useContext to manage a theme with CSS class toggling.
jsx
import { createContext, useContext, useState } from "react";
const ThemeContext = createContext();
function ThemeProvider({ children }) {
const [theme, setTheme] = useState("light");
const toggleTheme = () => setTheme(prev => (prev === "light" ? "dark" : "light"));
return <ThemeContext.Provider value={{ theme, toggleTheme }}>{children}</ThemeContext.Provider>;
}
function ThemedComponent() {
const { theme, toggleTheme } = useContext(ThemeContext);
const bgClass = theme === "light" ? "light-bg" : "dark-bg";
return (
<div className={bgClass}>
<button onClick={toggleTheme}>Toggle Theme</button>
<p>Current theme</p>
</div>
);
}
export default function ThemedApp() {
return (
<ThemeProvider>
<ThemedComponent />
</ThemeProvider>
);
}
67. Use useInsertionEffect (React 18) to inject CSS before layout effects (for CSS-in-JS).
jsx
import { useInsertionEffect } from "react";
function InsertionEffectDemo() {
useInsertionEffect(() => {
const style = document.createElement("style");
style.textContent = `.dynamic-class { color: red; }`;
document.head.appendChild(style);
return () => {
document.head.removeChild(style);
};
}, []);
return <div className="dynamic-class">Styled by injected CSS</div>;
}
export default InsertionEffectDemo;
68. Create a component that uses React.forwardRef with TypeScript-like prop types (plain JS example).
jsx
import { forwardRef } from "react";
const CustomInput = forwardRef((props, ref) => {
return <input ref={ref} {...props} />;
});
function ForwardRefWithProps() {
const inputRef = useRef();
const focus = () => inputRef.current.focus();
return (
<div>
<CustomInput ref={inputRef} placeholder="Focus me" />
<button onClick={focus}>Focus</button>
</div>
);
}
export default ForwardRefWithProps;
69. Build a component that renders a styled button using CSS modules (import styles).
jsx
// Assume Button.module.css has .button { background: blue; color: white; }
import styles from "./Button.module.css";
function CssModuleButton() {
return <button className={styles.button}>Styled Button</button>;
}
export default CssModuleButton;
70. Use React.PureComponent for a class component that should not re-render unnecessarily.
jsx
import React from "react";
class PureCounter extends React.PureComponent {
render() {
console.log("PureCounter rendered");
return <div>{this.props.count}</div>;
}
}
function PureParent() {
const [count, setCount] = React.useState(0);
return (
<div>
<button onClick={() => setCount(count + 1)}>Increment: {count}</button>
<PureCounter count={5} />
</div>
);
}
export default PureParent;
71. Create a component that uses React.memo with a function prop that changes (useCallback).
jsx
import { useState, useCallback } from "react";
const ChildWithFunction = React.memo(({ onClick }) => {
console.log("Child rendered");
return <button onClick={onClick}>Click</button>;
});
function ParentCallback() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
console.log("Clicked");
}, []);
return (
<div>
<button onClick={() => setCount(count + 1)}>Increment parent ({count})</button>
<ChildWithFunction onClick={handleClick} />
</div>
);
}
export default ParentCallback;
72. Implement a simple counter using class component with state.
jsx
import React from "react";
class ClassCounter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>Increment</button>
</div>
);
}
}
export default ClassCounter;
73. Build a component with localStorage persistence using useEffect to save state.
jsx
import { useState, useEffect } from "react";
function PersistedState() {
const [value, setValue] = useState(() => localStorage.getItem("myValue") || "");
useEffect(() => {
localStorage.setItem("myValue", value);
}, [value]);
return (
<div>
<input value={value} onChange={(e) => setValue(e.target.value)} />
<p>Stored value: {value}</p>
</div>
);
}
export default PersistedState;
74. Use React.Profiler to measure performance of a list component.
jsx
function SlowList() {
const items = Array.from({ length: 200 }, (_, i) => i);
return items.map(i => <div key={i}>Item {i}</div>);
}
function ProfiledList() {
const onRender = (id, phase, actualDuration) => {
console.log(`${id} ${phase} duration: ${actualDuration}`);
};
return (
<Profiler id="SlowList" onRender={onRender}>
<SlowList />
</Profiler>
);
}
export default ProfiledList;
75. Create a component that implements a simple tab interface using state.
jsx
import { useState } from "react";
function Tabs() {
const [activeTab, setActiveTab] = useState(0);
const tabs = ["Tab 1", "Tab 2", "Tab 3"];
const content = ["Content for tab 1", "Content for tab 2", "Content for tab 3"];
return (
<div>
<div style={{ display: "flex", gap: "10px" }}>
{tabs.map((tab, idx) => (
<button key={idx} onClick={() => setActiveTab(idx)} style={{ fontWeight: activeTab === idx ? "bold" : "normal" }}>
{tab}
</button>
))}
</div>
<div style={{ marginTop: "10px" }}>{content[activeTab]}</div>
</div>
);
}
export default Tabs;
76. Use useCallback together with useEffect to avoid stale closures.
jsx
import { useState, useCallback, useEffect } from "react";
function StaleClosureDemo() {
const [count, setCount] = useState(0);
const logCount = useCallback(() => {
console.log("Count:", count);
}, [count]);
useEffect(() => {
const interval = setInterval(() => logCount(), 2000);
return () => clearInterval(interval);
}, [logCount]);
return <button onClick={() => setCount(c => c + 1)}>Increment ({count})</button>;
}
export default StaleClosureDemo;
77. Build a component that renders an iframe with a title prop (and handle sandbox).
jsx
function IframeComponent({ title, src }) {
return <iframe title={title} src={src} sandbox="allow-same-origin allow-scripts" style={{ width: "100%", height: "300px" }} />;
}
function IframeDemo() {
return <IframeComponent title="Example" src="https://www.example.com" />;
}
export default IframeDemo;
Also try it: 100 Node.js practice problems with solutions
78. Create a component that uses React.createElement to produce a fragment.
jsx
function FragmentElement() {
return React.createElement(
React.Fragment,
null,
React.createElement("p", null, "First"),
React.createElement("p", null, "Second")
);
}
export default FragmentElement;
79. Use usePrompt (custom hook) to warn before leaving page (block navigation).
jsx
// Not built-in; simulate with beforeunload and Router
import { useEffect } from "react";
function useUnsavedChanges(condition, message = "You have unsaved changes") {
useEffect(() => {
const handleBeforeUnload = (e) => {
if (condition) {
e.preventDefault();
e.returnValue = message;
}
};
window.addEventListener("beforeunload", handleBeforeUnload);
return () => window.removeEventListener("beforeunload", handleBeforeUnload);
}, [condition, message]);
}
function UnsavedForm() {
const [dirty, setDirty] = useState(false);
useUnsavedChanges(dirty);
return (
<input placeholder="Type something" onChange={() => setDirty(true)} />
);
}
export default UnsavedForm;
80. Implement a component that uses React.use (React 19) to read a promise in render (concept).
jsx
// React 19 feature - not yet stable; use Suspense with data fetching libraries. // Example of using third-party Suspense integration.
81. Build a component that uses React.Children to detect if there is any child.
jsx
function HasChildren({ children }) {
const hasChildren = React.Children.count(children) > 0;
return <div>{hasChildren ? "Has children" : "No children"}</div>;
}
function ChildTest() {
return (
<div>
<HasChildren><span>a</span></HasChildren>
<HasChildren></HasChildren>
</div>
);
}
export default ChildTest;
82. Use useDebugValue with a custom hook that formats a timestamp.
jsx
import { useState, useDebugValue, useEffect } from "react";
function useTime() {
const [time, setTime] = useState(new Date());
useDebugValue(time, (date) => date.toLocaleTimeString());
useEffect(() => {
const interval = setInterval(() => setTime(new Date()), 1000);
return () => clearInterval(interval);
}, []);
return time;
}
function TimeDisplay() {
const time = useTime();
return <div>{time.toLocaleTimeString()}</div>;
}
export default TimeDisplay;
83. Create a component that renders an ordered list from an array using reduce in JSX.
jsx
function FromReduce() {
const items = ["A", "B", "C"];
const list = items.reduce((acc, item, idx) => {
acc.push(<li key={idx}>{item}</li>);
return acc;
}, []);
return <ul>{list}</ul>;
}
export default FromReduce;
84. Use React.startTransition to mark a state update as non‑urgent (outside of hooks).
jsx
import { useState, startTransition } from "react";
function HeavyUpdate() {
const [value, setValue] = useState(0);
const handleClick = () => {
startTransition(() => {
setValue(v => v + 1);
});
};
return <button onClick={handleClick}>Increment (non‑urgent) {value}</button>;
}
export default HeavyUpdate;
85. Build a component that uses useId to generate unique IDs for multiple inputs and labels.
jsx
import { useId } from "react";
function FormWithIds() {
const nameId = useId();
const emailId = useId();
return (
<div>
<div>
<label htmlFor={nameId}>Name:</label>
<input id={nameId} type="text" />
</div>
<div>
<label htmlFor={emailId}>Email:</label>
<input id={emailId} type="email" />
</div>
</div>
);
}
export default FormWithIds;
86. Use React.Children.map to conditionally wrap children with a tooltip.
jsx
import React from "react";
function TooltipWrapper({ children }) {
return React.Children.map(children, (child) => {
if (React.isValidElement(child)) {
return React.cloneElement(child, { title: "Tooltip content" });
}
return child;
});
}
function Tooltipped() {
return (
<TooltipWrapper>
<button>Button 1</button>
<button>Button 2</button>
</TooltipWrapper>
);
}
export default Tooltipped;
87. Implement a component that uses React.memo with a functional component and a complex prop that changes occasionally.
jsx
import { useState, useMemo } from "react";
const ComplexChild = React.memo(({ data }) => {
console.log("ComplexChild rendered");
return <div>{data.join(", ")}</div>;
});
function ParentComplex() {
const [count, setCount] = useState(0);
const data = useMemo(() => [1, 2, 3], []);
return (
<div>
<button onClick={() => setCount(count + 1)}>Increment: {count}</button>
<ComplexChild data={data} />
</div>
);
}
export default ParentComplex;
88. Create a component that renders a Bootstrap card (using Bootstrap CSS classes).
jsx
function BootstrapCard({ title, text }) {
return (
<div className="card" style={{ width: "18rem" }}>
<div className="card-body">
<h5 className="card-title">{title}</h5>
<p className="card-text">{text}</p>
<button className="btn btn-primary">Go somewhere</button>
</div>
</div>
);
}
export default BootstrapCard;
89. Use React.Fragment to return multiple elements without extra DOM node.
jsx
function FragmentExample() {
return (
<React.Fragment>
<h1>Title</h1>
<p>Paragraph</p>
</React.Fragment>
);
}
export default FragmentExample;
90. Build a component that uses useEffect to set the document title.
jsx
import { useState, useEffect } from "react";
function DocumentTitle() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]);
return <button onClick={() => setCount(count + 1)}>Click me</button>;
}
export default DocumentTitle;
91. Use ReactDOM.render (legacy) to mount component (not recommended, but for understanding).
jsx
import React from "react";
import ReactDOM from "react-dom";
function OldSchool() {
return <div>Legacy render</div>;
}
// In index.js: ReactDOM.render(<OldSchool />, document.getElementById("root"));
// Now uses createRoot.
92. Create a component that uses useReducer with initializer function.
jsx
import { useReducer } from "react";
const init = (initialCount) => {
return { count: initialCount };
};
const reducer = (state, action) => {
switch (action.type) {
case "increment": return { count: state.count + 1 };
default: return state;
}
};
function InitializerReducer() {
const [state, dispatch] = useReducer(reducer, 10, init);
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: "increment" })}>+</button>
</div>
);
}
export default InitializerReducer;
93. Implement a simple stepper (wizard) component using state and conditional rendering.
jsx
import { useState } from "react";
function Stepper() {
const [step, setStep] = useState(1);
const next = () => setStep(s => Math.min(s + 1, 3));
const prev = () => setStep(s => Math.max(s - 1, 1));
return (
<div>
<div>Step {step} of 3</div>
{step === 1 && <div>Step 1: Enter name</div>}
{step === 2 && <div>Step 2: Enter email</div>}
{step === 3 && <div>Step 3: Confirmation</div>}
<div>
<button onClick={prev} disabled={step === 1}>Previous</button>
<button onClick={next} disabled={step === 3}>Next</button>
</div>
</div>
);
}
export default Stepper;
94. Use useLayoutEffect to measure and set state for an element’s height.
jsx
import { useLayoutEffect, useRef, useState } from "react";
function MeasuredDiv() {
const divRef = useRef();
const [height, setHeight] = useState(0);
useLayoutEffect(() => {
setHeight(divRef.current.clientHeight);
}, []);
return (
<div>
<div ref={divRef} style={{ padding: "20px", background: "lightgray" }}>
<p>Content that might wrap</p>
</div>
<p>Height: {height}px</p>
</div>
);
}
export default MeasuredDiv;
95. Create a component that uses React.createRef (class component) to focus input.
jsx
import React from "react";
class ClassRef extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
focusInput = () => {
this.inputRef.current.focus();
};
render() {
return (
<div>
<input ref={this.inputRef} type="text" />
<button onClick={this.focusInput}>Focus</button>
</div>
);
}
}
export default ClassRef;
96. Use React.cloneElement with children to pass a new prop to a specific child.
jsx
function InjectProp({ children }) {
return React.Children.map(children, (child) => {
if (child.type === "button") {
return React.cloneElement(child, { style: { backgroundColor: "yellow" } });
}
return child;
});
}
function InjectDemo() {
return (
<InjectProp>
<button>Button 1</button>
<span>Not a button</span>
<button>Button 2</button>
</InjectProp>
);
}
export default InjectDemo;
97. Build a component that uses useContext and useReducer to create a notification system.
jsx
import { createContext, useContext, useReducer } from "react";
const NotificationContext = createContext();
const notificationReducer = (state, action) => {
switch (action.type) {
case "add": return [action.message, ...state];
case "remove": return state.slice(1);
default: return state;
}
};
function NotificationProvider({ children }) {
const [notifications, dispatch] = useReducer(notificationReducer, []);
const addNotification = (msg) => dispatch({ type: "add", message: msg });
const removeOldest = () => dispatch({ type: "remove" });
return (
<NotificationContext.Provider value={{ notifications, addNotification, removeOldest }}>
{children}
<div style={{ position: "fixed", bottom: 10, right: 10 }}>
{notifications.map((n, i) => <div key={i}>{n}</div>)}
</div>
</NotificationContext.Provider>
);
}
function NotifyButton() {
const { addNotification } = useContext(NotificationContext);
return <button onClick={() => addNotification("Notification!")}>Notify</button>;
}
function NotificationApp() {
return (
<NotificationProvider>
<NotifyButton />
</NotificationProvider>
);
}
export default NotificationApp;
98. Use React.Children.toArray to sort children by a prop.
jsx
function SortChildren({ children }) {
const sorted = React.Children.toArray(children).sort((a, b) => {
return a.props.priority - b.props.priority;
});
return <div>{sorted}</div>;
}
function SortDemo() {
return (
<SortChildren>
<div priority={3}>Third</div>
<div priority={1}>First</div>
<div priority={2}>Second</div>
</SortChildren>
);
}
export default SortDemo;
Also try it: 100 jquery practice problems with solutions
99. Create a component that uses React.forwardRef to expose a DOM element’s methods.
jsx
const FocusableInput = forwardRef((props, ref) => {
return <input ref={ref} {...props} />;
});
function ParentWithRef() {
const inputRef = useRef();
const focus = () => inputRef.current.focus();
return (
<div>
<FocusableInput ref={inputRef} placeholder="Type here" />
<button onClick={focus}>Focus</button>
</div>
);
}
export default ParentWithRef;
100. Build a weather widget component that fetches weather from an API (OpenWeatherMap).
jsx
import { useState, useEffect } from "react";
function WeatherWidget({ city }) {
const [weather, setWeather] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const apiKey = "YOUR_API_KEY";
fetch(`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}&units=metric`)
.then(res => res.json())
.then(data => {
setWeather(data);
setLoading(false);
})
.catch(err => {
console.error(err);
setLoading(false);
});
}, [city]);
if (loading) return <div>Loading weather...</div>;
if (!weather || weather.cod !== 200) return <div>Weather not found</div>;
return (
<div>
<h3>{weather.name}</h3>
<p>Temperature: {weather.main.temp}°C</p>
<p>Condition: {weather.weather[0].description}</p>
</div>
);
}
export default WeatherWidget;
Final Thought
One hundred React problems — and you’re still standing taller than ever. Let that sink in. You didn’t just glance at code; you built components, managed state, handled events, fetched data, and debugged your way through real challenges. Each problem cracked open a little more certainty inside you. That feeling? That quiet, unshakable voice whispering “I can handle this” — that’s real confidence, earned the honest way.
React can feel like a jungle when you start — so many hooks, patterns, and moving pieces. But you kept walking through it, one step at a time, and now you can see the clearing. You’re not guessing anymore; you’re deciding. You’re not copying; you’re creating. That shift is everything.
Bookmark this collection as proof of how far you’ve come. On days when self-doubt knocks, open it and solve just one problem — not to prove you still know React, but to remind yourself you never stopped. You belong in this community of builders. You have the skills, the grit, and now the proof. Walk into that interview, that project, that next big idea with your head high. You’re a React developer — truly, deeply, confidently. Now go build something amazing.