REACT Scenario-Based Questions

scenario-based React interview questions that assess your problem-solving skills and your ability to apply React concepts in real-world situations:

1. Scenario: Optimizing Performance in a Large Application

Question: You have a large React application with many components, and it is becoming slow due to unnecessary re-renders. How would you optimize the performance of this application?

 

Answer:

  • Use React.memo for functional components and PureComponent for class components to prevent unnecessary re-renders.
  • Implement shouldComponentUpdate lifecycle method for class components to control re-renders.
  • Use useMemo and useCallback hooks to memoize values and functions that don’t need to be recalculated on each render.
  • Implement code-splitting using React.lazy and Suspense to load only necessary components.
  • Optimize images and assets by using lazy loading.
  • Use React DevTools to identify performance bottlenecks.

2. Scenario: Managing API Calls in a Component

Question: You are building a React app that needs to fetch data from an API when the component mounts. How do you manage this API call and handle the loading, error, and success states?

 

Answer:

  • Use the useEffect hook to make the API call when the component mounts.
  • Maintain the API response in a state using useState.
  • Handle loading and error states using additional state variables.
  • Display a loading spinner while waiting for the data and show error messages if the API call fails.
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);

useEffect(() => {
  fetch('https://api.example.com/data')
    .then(response => response.json())
    .then(data => {
      setData(data);
      setLoading(false);
    })
    .catch(err => {
      setError(err);
      setLoading(false);
    });
}, []);

if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <div>Data: {JSON.stringify(data)}</div>;

Try It Now

3. Scenario: Handling Complex Forms with Validation

Question: You are tasked with building a form with complex validation, including checking for required fields, email format, and password strength. How would you implement this in React?

 

Answer:

  • Use controlled components for form fields and manage the form state with useState.
  • Implement custom validation functions for each field.
  • Use libraries like Formik or React Hook Form to handle form state, validation, and submission.
  • Display error messages next to the corresponding fields when validation fails.
  • You can also use Yup for schema-based validation with Formik.
const [formData, setFormData] = useState({ email: '', password: '' });
const [errors, setErrors] = useState({ email: '', password: '' });

const handleChange = (e) => {
  const { name, value } = e.target;
  setFormData((prev) => ({ ...prev, [name]: value }));
};

const validateForm = () => {
  let errors = {};
  if (!formData.email) errors.email = "Email is required";
  if (!/\S+@\S+\.\S+/.test(formData.email)) errors.email = "Invalid email format";
  if (formData.password.length < 8) errors.password = "Password must be at least 8 characters";
  setErrors(errors);
  return Object.keys(errors).length === 0;
};

const handleSubmit = (e) => {
  e.preventDefault();
  if (validateForm()) {
    console.log("Form submitted:", formData);
  }
};

return (
  <form onSubmit={handleSubmit}>
    <input type="email" name="email" value={formData.email} onChange={handleChange} />
    {errors.email && <div>{errors.email}</div>}
    <input type="password" name="password" value={formData.password} onChange={handleChange} />
    {errors.password && <div>{errors.password}</div>}
    <button type="submit">Submit</button>
  </form>
);

Try It Now

4. Scenario: Avoiding Prop Drilling

Question: You have a deeply nested component tree and you need to pass data from the top-most parent to a child component located at a deep level. How would you avoid “prop drilling”?

 

Answer:

  • Use React Context to provide and consume data without passing props manually at every level.
  • Define a context at the top level and wrap the components that need access to the data.
  • Use the useContext hook in the child components to access the context values.
const UserContext = React.createContext();

const ParentComponent = () => {
  const user = { name: "John Doe" };

  return (
    <UserContext.Provider value={user}>
      <ChildComponent />
    </UserContext.Provider>
  );
};

const ChildComponent = () => {
  const user = useContext(UserContext);
  return <div>Hello, {user.name}</div>;
};

Try It Now

5. Scenario: Authentication and Protected Routes

Question: How would you implement a basic authentication system in a React app, ensuring that some routes are protected and only accessible by authenticated users?

 

Answer:

  • Use React Context or a state management library like Redux to store authentication state (e.g., whether the user is logged in or not).
  • Create a PrivateRoute component that checks the authentication state and either renders the protected component or redirects to the login page.
  • Use React Router for navigation and routing.

 

const AuthContext = React.createContext();

const PrivateRoute = ({ children }) => {
  const { isAuthenticated } = useContext(AuthContext);
  return isAuthenticated ? children : <Redirect to="/login" />;
};

const App = () => {
  const [isAuthenticated, setIsAuthenticated] = useState(false);

  return (
    <AuthContext.Provider value={{ isAuthenticated, setIsAuthenticated }}>
      <BrowserRouter>
        <Route path="/login" component={Login} />
        <PrivateRoute path="/dashboard">
          <Dashboard />
        </PrivateRoute>
      </BrowserRouter>
    </AuthContext.Provider>
  );
};

Try It Now

6. Scenario: Lazy Loading Components

Question: You have a React app that contains several large components. How would you implement lazy loading to improve performance?

 

Answer:

  • Use React.lazy and Suspense to lazy-load components only when they are needed.
  • Wrap the lazy-loaded component in a Suspense component to display a fallback UI (like a spinner) while the component is being loaded.
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));

const App = () => (
  <Suspense fallback={<div>Loading...</div>}>
    <HeavyComponent />
  </Suspense>
);

Try It Now

7. Scenario: Error Handling in React

Question: You need to catch errors in your React components and display a fallback UI without crashing the entire application. How would you implement this?

 

Answer:

  • Use Error Boundaries to catch JavaScript errors in their child component tree, log those errors, and display a fallback UI.
  • Error boundaries are implemented by creating a class component that defines componentDidCatch lifecycle method.
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    console.log(error, info);
  }

  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong!</h1>;
    }
    return this.props.children;
  }
}

const App = () => (
  <ErrorBoundary>
    <SomeComponent />
  </ErrorBoundary>
);

Try It Now

 

8. Scenario: Conditional Rendering

Question:
You have a component that displays a user’s profile. If the user is logged in, it should show their name and a logout button. If the user is not logged in, it should show a login button. How would you implement this in React?

 

Answer:

function UserProfile({ isLoggedIn, userName, onLogin, onLogout }) {
  return (
    <div>
      {isLoggedIn ? (
        <div>
          <p>Welcome, {userName}!</p>
          <button onClick={onLogout}>Logout</button>
        </div>
      ) : (
        <button onClick={onLogin}>Login</button>
      )}
    </div>
  );
}

Try It Now

Explanation:

  • Use a ternary operator to conditionally render content based on the isLoggedIn prop.
  • If isLoggedIn is true, display the user’s name and a logout button.
  • If isLoggedIn is false, display a login button.

 

9. Scenario: Lifting State Up

Question:
You have two sibling components: InputComponent and DisplayComponent. The InputComponent should take user input, and the DisplayComponent should display it. How would you implement this?

 

Answer:

import React, { useState } from 'react';

function ParentComponent() {
  const [inputValue, setInputValue] = useState('');

  const handleInputChange = (e) => {
    setInputValue(e.target.value);
  };

  return (
    <div>
      <InputComponent value={inputValue} onChange={handleInputChange} />
      <DisplayComponent value={inputValue} />
    </div>
  );
}

function InputComponent({ value, onChange }) {
  return (
    <input type="text" value={value} onChange={onChange} />
  );
}

function DisplayComponent({ value }) {
  return <p>You typed: {value}</p>;
}

Try It Now

Explanation:

  • Lift the state up to the parent component (ParentComponent).
  • Pass the state and handler function as props to InputComponent.
  • Pass the state as a prop to DisplayComponent.

 

 

 

 

10. Scenario: React Context API

Question:
You need to share a theme (light/dark) across multiple components without prop drilling. How would you implement this using the React Context API?

Answer:

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

const ThemeContext = createContext();

function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');

  const toggleTheme = () => {
    setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

function ThemedButton() {
  const { theme, toggleTheme } = useContext(ThemeContext);
  return (
    <button onClick={toggleTheme} style={{ background: theme === 'light' ? '#fff' : '#333', color: theme === 'light' ? '#000' : '#fff' }}>
      Toggle Theme
    </button>
  );
}

function App() {
  return (
    <ThemeProvider>
      <ThemedButton />
    </ThemeProvider>
  );
}

Try It Now

Explanation:

  • Create a ThemeContext using createContext.
  • Use a ThemeProvider to wrap the components that need access to the theme.
  • Use the useContext hook to consume the context in child components.

 

11. Scenario: React Router

Question:
You need to create a simple app with two pages: a Home page and an About page. How would you implement this using React Router?

Answer:

import React from 'react';
import { BrowserRouter as Router, Route, Routes, Link } from 'react-router-dom';

function Home() {
  return <h1>Home Page</h1>;
}

function About() {
  return <h1>About Page</h1>;
}

function App() {
  return (
    <Router>
      <nav>
        <Link to="/">Home</Link>
        <Link to="/about">About</Link>
      </nav>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </Router>
  );
}

Try It Now

Explanation:

  • Use react-router-dom to set up routing.
  • Define routes using the Routes and Route components.
  • Use the Link component for navigation.

 

These scenarios cover a range of real-world challenges you may face while working with React.