Top 10 ReactJS Coding Interview Challenge For 2024

Ravi Sharma
JavaScript in Plain English
9 min readJan 25, 2024

--

This article aims to provide an insightful exploration of coding challenges, and essential best practices for acing ReactJS interviews. By delving into the core concepts and practical scenarios, readers will gain a comprehensive understanding of what to expect in ReactJS coding interviews.

Task-1: Fetch the users list and display

Write code to fetch the user's details from the open source rest endpoint and display the user's details in the table with proper style and in the center.

import React, { useEffect, useState } from 'react';
import "./styles.css";

const App = () => {
const [users, setUsers] = useState([])

useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then((result) => result.json())
.then((data) => {
console.log("users", data)
setUsers(data)
})
.catch(error => console.error('Error fetching user data:', error));
}, []);

return (
<div style={{ textAlign: 'center' }}>
<h1>User Details Table</h1>
<table style={{ borderCollapse: 'collapse', margin: 'auto', width: '60%', border: '1px solid #ddd' }}>
<thead>
<tr style={{ border: '1px solid #ddd', backgroundColor: 'black', color: 'white' }}>
<th>Name</th>
<th>Email</th>
<th>Mobile</th>
</tr>
</thead>
<tbody>
{
users.length &&
users.map((item) => (
<tr style={{ border: '1px solid #ddd', backgroundColor: 'gray', color: 'white' }}>
<td>{item.name}</td>
<td>{item.email}</td>
<td>{item.phone}</td>
</tr>
))
}
</tbody>
</table>
</div>
)
}
export default App;

Alternate Approach:

What If I want to use the Axios library to fetch users' details?

import React, { useState, useEffect } from 'react';
import axios from 'axios';
import './UserTable.css';

function UserTable() {
const [users, setUsers] = useState([]);

useEffect(() => {
axios.get('https://jsonplaceholder.typicode.com/users') // Using Axios to fetch user details
.then(response => {
setUsers(response.data);
})
.catch(error => {
console.error('Error fetching user data:', error);
});
}, []);

return (
<div className="user-table-container">
<h2>User Details</h2>
<table className="user-table">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Phone</th>
<th>Website</th>
</tr>
</thead>
<tbody>
{users.map(user => (
<tr key={user.id}>
<td>{user.name}</td>
<td>{user.email}</td>
<td>{user.phone}</td>
<td>{user.website}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}

export default UserTable;

Task-2: Implement Search Functionality

Fetch the user details and display user names. Also, implement a search bar functionality on the username.

import React, { useState, useEffect } from 'react';

const UserList = () => {
const [users, setUsers] = useState([]);
const [searchTerm, setSearchTerm] = useState('');

useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users') // Fetching user details from the given endpoint
.then(response => response.json())
.then(data => setUsers(data))
.catch(error => console.error('Error fetching user data:', error));
}, []);

const filteredUsers = users.filter(user =>
user.name.toLowerCase().includes(searchTerm.toLowerCase())
);

return (
<div>
<h2>User List</h2>
<input
type="text"
placeholder="Search by username"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
<ul>
{filteredUsers.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
);
};

export default UserList;

Task-3: Optimized Search Using debounce and cancelable technique

Improve the search functionality using debounce and cancelable request and display filtered user details only.

import { useState, useEffect } from "react";

const App = () => {
const [usersData, setUsersData] = useState([]);
const [searchText, setSearchText] = useState("");
const [filteredUser, setFilteredUser] = useState({});

useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/users")
.then((res) => res.json())
.then((data) => {
console.log("fetched data", data);
setUsersData(data);
})
.catch((error) => {
console.log("Errror While fetching user data");
});
}, []);

useEffect(() => {
const abortController = new AbortController();
const filterTimer = setTimeout(() => {
try {
fetch(
`https://jsonplaceholder.typicode.com/users?username=${searchText}`,
{
signal: abortController.signal, // Pass the AbortController's signal to the fetch request
}
)
.then((response) => response.json())
.then((data) => {
console.log("FilteredUser ", data);
setFilteredUser(data[0]);
});
} catch (error) {
if (error.name === "AbortError") {
console.log("Request was aborted");
} else {
console.error("Error fetching user data:", error);
}
}
}, 300);

return () => {
abortController.abort();
clearTimeout(filterTimer);
};
}, [searchText]);

const handleSearch = (value) => {
setSearchText(value);
};

return (
<div style={{ textAlign: "center" }}>
<h4>Users Data</h4>
<input
type="text"
placeholder="Search by username"
value={searchText}
onChange={(e) => handleSearch(e.target.value)}
/>

<table
style={{
borderCollapse: "collapse",
margin: "auto",
border: "1px solid red",
}}
>
<thead>
<tr>
<th>Name</th>
<th>Username</th>
<th>Email</th>
</tr>
</thead>

<tbody>
{usersData &&
usersData.map((user) => (
<tr key={user.id}>
<td>{user.name}</td>
<td>{user.username}</td>
<td>{user.email}</td>
</tr>
))}
</tbody>
</table>

<div>
<h4>Search Result</h4>
{filteredUser && filteredUser.name}
</div>
</div>
);
};

export default App;

Task-4: Implement Sort By Username functionality

Write code to fetch the user’s details and display the usernames. There should be two buttons to sort usernames in ascending order and descending order.

import { useState, useEffect } from "react";

const App = () => {
const [usersData, setUsersData] = useState([]);

useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/users")
.then((res) => res.json())
.then((data) => {
setUsersData(data);
})
.catch((error) => {
throw error;
});
}, []);

const handleAscendingSort = () => {
const users = [...usersData].sort((a, b) =>
a.username.localeCompare(b.username)
);
setUsersData(users);
};

const handleDescendingSort = () => {
const users = [...usersData].sort((a, b) =>
b.username.localeCompare(a.username)
);
setUsersData(users);
};

return (
<div className="App">
<h1>Example of short by username</h1>
<button onClick={() => handleAscendingSort()}>
Short by Ascending
</button>
<button onClick={() => handleDescendingSort()}>
Short by Descending
</button>
{usersData &&
usersData.map((user) => (
<div key={user.id}>
<p>{user.username}</p>
</div>
))}
</div>
);
}

export default App;

Task-5: Create Signup Form Controlled Component

Create a user registration form with fields for username, email, and password. Validate inputs and display appropriate error messages. (Create a controlled form component with a state to manage input values.)

import React, { useState } from 'react';
import * as Yup from 'yup'; // Import Yup for form validation
import './UserRegistrationForm.css'; // Import the CSS file for the component

const UserRegistrationForm = () => {
const [formData, setFormData] = useState({
firstName: '',
lastName: '',
email: '',
password: '',
});

const [errors, setErrors] = useState({});
const [successMessage, setSuccessMessage] = useState('');
const [loading, setLoading] = useState(false);
const schema = Yup.object().shape({
firstName: Yup.string().required('First Name is required'),
lastName: Yup.string().required('Last Name is required'),
email: Yup.string().email('Invalid email').required('Email is required'),
password: Yup.string().required('Password is required').min(6, 'Password must be at least 6 characters'),
});

const validateField = async (name, value) => {
try {
await schema.validateAt(name, { [name]: value });
setErrors(prevErrors => ({ ...prevErrors, [name]: '' }));
} catch (error) {
setErrors(prevErrors => ({ ...prevErrors, [name]: error.message }));
}
};

const handleChange = async (e) => {
const { name, value } = e.target;
setFormData(prevData => ({ ...prevData, [name]: value }));
await validateField(name, value);
};

const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
try {
await schema.validate(formData, { abortEarly: false });
// Simulate API call with a delay
setTimeout(() => {
setLoading(false);
setSuccessMessage('Registration successful!');
}, 2000);
} catch (error) {
const validationErrors = {};
error.inner.forEach(fieldError => {
validationErrors[fieldError.path] = fieldError.message;
});
setErrors(validationErrors);
setLoading(false);
}
};

return (
<div>
<h2>User Registration</h2>
<form onSubmit={handleSubmit}>
<div>
<input type="text" name="firstName" value={formData.firstName} onChange={handleChange} />
{errors.firstName && <span className="error-message">{errors.firstName}</span>}
</div>
<div>
<input type="text" name="lastName" value={formData.lastName} onChange={handleChange} />
{errors.lastName && <span className="error-message">{errors.lastName}</span>}
</div>
<div>
<input type="email" name="email" value={formData.email} onChange={handleChange} />
{errors.email && <span className="error-message">{errors.email}</span>}
</div>
<div>
<input type="password" name="password" value={formData.password} onChange={handleChange} />
{errors.password && <span className="error-message">{errors.password}</span>}
</div>
<button type="submit" disabled={loading}>{loading ? 'Submitting...' : 'Submit'}</button>
</form>
{successMessage && <div className="success-message">{successMessage}</div>}
</div>
);
};

export default UserRegistrationForm;

Task-6: Dark and Light Mode

Implement the logic to change the app display mode using context API.

-DisplayModeContext.js file

import React, { createContext, useState, useContext } from "react";

// Create a context for the display mode
const DisplayModeContext = createContext();

// Create a custom hook to use the display mode context
export const useDisplayMode = () => {
return useContext(DisplayModeContext);
};

// Create a provider component for the display mode context
export const DisplayModeProvider = ({ children }) => {
const [displayMode, setDisplayMode] = useState("light"); // Default display mode is 'light'

const toggleDisplayMode = () => {
setDisplayMode((prevMode) => (prevMode === "light" ? "dark" : "light")); // Toggle between 'light' and 'dark' mode
};

return (
<DisplayModeContext.Provider value={{ displayMode, toggleDisplayMode }}>
{children}
</DisplayModeContext.Provider>
);
};

-App.js file

import "./styles.css";
import { useDisplayMode } from "./DisplayModeContext";

export default function App() {
const { displayMode, toggleDisplayMode } = useDisplayMode();

const appStyle = {
background: displayMode === "light" ? "#ffffff" : "#333333",
color: displayMode === "light" ? "#333333" : "#ffffff",
padding: "5px",
};

return (
<div style={appStyle}>
<h3>Press below button to change the display mode</h3>
<button onClick={() => toggleDisplayMode()}>
{displayMode === "light" ? "Dark Mode" : "Light Mode"}
</button>
</div>
);
}

-index.js

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";

import App from "./App";
import { DisplayModeProvider } from "./DisplayModeContext";

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(
<StrictMode>
<DisplayModeProvider>
<App />
</DisplayModeProvider>
</StrictMode>
);

Task-7: Task ToDO List

Create a simple to-do list application where you can add, and remove tasks from the list.

import { useState } from "react";

export default function App() {
const [taskList, setTaskList] = useState([]);
const [taskDetail, setTaskDetail] = useState("");

const handleAddTask = () => {
setTaskList([...taskList, taskDetail]);
setTaskDetail("");
};

const handleRemoveTask = (index) => {
const newTaskList = [...taskList];
newTaskList.splice(index, 1);
setTaskList(newTaskList);
};

const handleTaskUpdate = (value) => {
setTaskDetail(value);
};

return (
<div>
<>
<h3>ToDO List</h3>
<input
type="text"
placeholder="Add task detail here"
value={taskDetail}
onChange={(e) => handleTaskUpdate(e.target.value)}
/>
<button onClick={() => handleAddTask()}>Add</button>
</>
<>
<ul>
{taskList &&
taskList.map((item, index) => (
<div key={index}>
<li>
{item}{" "}
<button onClick={() => handleRemoveTask(index)}>
Remove
</button>
</li>
</div>
))}
</ul>
</>
</div>
);
}

Task-8: Shopping Cart Component

Prepare JSON data for shopping items and implement a shopping cart app where users can add items, update the number of items, remove items, and display the final amount for the total order.

-items.json

// items.json
{
"items": [
{
"id": 1,
"name": "T-shirt",
"price": 20
},
{
"id": 2,
"name": "Jeans",
"price": 50
},
{
"id": 3,
"name": "Shoes",
"price": 80
}
]
}

-App.js

import { useState } from "react";
import "./styles.css";
import itemsData from "./items.json";

export default function App() {
const [items, setItems] = useState(itemsData.items);
const [cart, setCart] = useState([]);

const addToCart = (itemId) => {
const selectedItem = items.find((item) => item.id === itemId);
const itemInCart = cart.find((item) => item.id === itemId);

if (itemInCart) {
const updatedCart = cart.map((item) => {
if (item.id === itemId) {
return { ...item, quantity: (item.quantity || 1) + 1 };
}
return item;
});
setCart(updatedCart);
} else {
setCart([...cart, { ...selectedItem, quantity: 1 }]);
}
};

const removeFromCart = (itemId) => {
const updatedCart = cart.filter((item) => item.id !== itemId);
setCart(updatedCart);
};

const updateQuantity = (itemId, newQuantity) => {
if (newQuantity > 5) {
return; // Prevent updating quantity beyond 5
}
const updatedCart = cart.map((item) => {
if (item.id === itemId) {
return { ...item, quantity: newQuantity };
}
return item;
});
setCart(updatedCart);
};

const calculateTotal = () => {
return cart.reduce(
(total, item) => total + item.price * (item.quantity || 1),
0
);
};

return (
<div>
<h1>Shopping Cart</h1>
<h2>Available Items</h2>
<ul>
{items.map((item) => (
<li key={item.id}>
{item.name} - ${item.price}
<button onClick={() => addToCart(item.id)}>Add to Cart</button>
</li>
))}
</ul>
<h2>Cart Total</h2>
<ul>
{cart.map((item) => (
<li key={item.id}>
{item.name} - ${item.price} -
<select
value={item.quantity || 1}
onChange={(e) =>
updateQuantity(item.id, parseInt(e.target.value))
}
>
{[...Array(5).keys()].map((number) => (
<option key={number + 1} value={number + 1}>
{number + 1}
</option>
))}
</select>
<button onClick={() => removeFromCart(item.id)}>Remove</button>
</li>
))}
</ul>
<h2>Total: ${calculateTotal()}</h2>
</div>
);
}

Task-9: Pagination Component

Build a pagination component that fetches and displays data from an API, showing a fixed number of items per page

-paginated.js

import React, { useState, useEffect } from "react";

const PaginationComponent = ({ apiUrl, itemsPerPage }) => {
const [data, setData] = useState([]);
const [currentPage, setCurrentPage] = useState(1);
const [totalPages, setTotalPages] = useState(null);

useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(
`${apiUrl}?_page=${currentPage}&_limit=${itemsPerPage}`
);
// Assuming the API responds with JSON data
const jsonData = await response.json();
setData(jsonData);
// Retrieving total count of items from the API response headers
const totalCount = response.headers.get("X-Total-Count");
setTotalPages(Math.ceil(totalCount / itemsPerPage));
} catch (error) {
console.error("Error fetching data:", error);
}
};

fetchData();
}, [apiUrl, currentPage, itemsPerPage]);

const handlePageChange = (newPage) => {
setCurrentPage(newPage);
};

return (
<div>
<ol>
{data.map((item) => (
<li key={item.id}>{item.title}</li> // Assuming 'name' is the property to display
))}
</ol>
<div>
<button
onClick={() => handlePageChange(currentPage - 1)}
disabled={currentPage === 1}
>
Previous
</button>
<span>
Page {currentPage} of {totalPages}
</span>
<button
onClick={() => handlePageChange(currentPage + 1)}
disabled={currentPage === totalPages}
>
Next
</button>
</div>
</div>
);
};

export default PaginationComponent;

-App.js

import PaginationComponent from "./paginated";

const App = () => {
return (
<div>
<h1>Pagination Example</h1>
<PaginationComponent
apiUrl="https://jsonplaceholder.typicode.com/posts"
itemsPerPage={10}
/>
</div>
);
};

export default App;

Task-10: Infinite Scroll Gallery with Lazy Loading

Build an image gallery that loads more images as the user scrolls down the page. Implement lazy loading for improved performance.

import React, { useState, useEffect } from "react";
import "./styles.css";

const App = () => {
const [images, setImages] = useState([]);
const [page, setPage] = useState(1);
const [loading, setLoading] = useState(false);

const fetchImages = async () => {
setLoading(true);
try {
// use your client id by register developer account on unplash and create app.
const response = await fetch(
`https://api.unsplash.com/photos/?client_id=weJDI4C21OzgEkJD2ZSkb5yt1aBQwiuHh2tVK4tvS5w&page=${page}`
);
if (!response.ok) {
throw new Error("Failed to fetch");
}
const data = await response.json();
if (Array.isArray(data)) {
setImages((prevImages) => [...prevImages, ...data]);
setPage((prevPage) => prevPage + 1);
} else {
console.error("Invalid data format:", data);
}
} catch (error) {
console.error("Error fetching images:", error);
} finally {
setLoading(false);
}
};

useEffect(() => {
fetchImages();
}, []);

const handleScroll = () => {
if (
window.innerHeight + document.documentElement.scrollTop !==
document.documentElement.offsetHeight ||
loading
)
return;
fetchImages();
};

useEffect(() => {
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, [loading]);

return (
<div>
<h1>Image Gallery</h1>
<div className="image-gallery">
{images.map((image) => (
<img
key={image.id}
src={image.urls.small}
alt={image.alt_description}
/>
))}
{loading && <p>Loading...</p>}
</div>
</div>
);
};

export default App;

Hope you like this article. Thanks for reading.

Follow me on Medium for more interesting articles.

Other Platform:

Follow me on LinkedIn: https://www.linkedin.com/in/ravics09/

Follow me on X: https://twitter.com/JS_Centric?t=nyKrM6oaUigAUYNtsWkuUw&s=09

Subscribe to My YouTube channel: https://www.youtube.com/channel/UC9MmyicGIveu0AId8OFAOmQ

In Plain English 🚀

Thank you for being a part of the In Plain English community! Before you go:

--

--