Top Asked React Interview Q&A Part 2

Top Asked React Interview Q&A Part 2

1. Explain the differences between useMemo() and useCallback() in React

useMemo and useCallback are performance optimization hooks in React. While they might seem similar, they serve different purposes:

What is useMemo()?

useMemo is used to memoize computed values. It helps in avoiding expensive calculations on every render.

const expensiveValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

Let’s say you have a heavy calculation that depends on two variables a and b. Without useMemo, this calculation would re-run every time the component renders—even if a and b haven’t changed. That’s a waste of CPU cycles. So, useMemo helps you say, “Hey React, only re-run this if a or b changes, alright?” And React nods and says, “Got it, boss.”

What is useCallback()?

useCallback is used to memoize callback functions. This is especially useful when passing functions to child components to prevent unnecessary renders.

const handleClick = useCallback(() => console.log("Clicked!"), []);

Picture this: You’re passing a function to a child component. Every re-render of the parent creates a new function, which makes the child component think, “Whoa! New props! Time to re-render!” useCallback stops this madness by saying, “Chill out, React. This is the same function unless my dependencies change.”

Key Differences and When to Use What

  • useMemo -> memoizes returned value.
  • useCallback -> memoizes function reference.
  • Use useMemo for computational results.
  • Use useCallback when functions are passed as props.

In interviews, explain the difference with examples like above and emphasize performance optimization.


2. How would you implement dynamic form handling and validation in React?

Handling dynamic forms in React? You’re in for a wild ride! But don’t worry—we’ve got controlled components, hooks, and some libraries to help us stay sane.

Step 1: Manage Form State Dynamically

Use an object to hold field values:

const [formData, setFormData] = useState({ name: '', email: '' });

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

Step 2: Form Validation

You can validate on blur, on submit, or in real-time. Here’s an on-submit example:

const handleSubmit = (e) => {
  e.preventDefault();
  if (!formData.email.includes("@")) {
    alert("Please enter a valid email");
    return;
  }
  console.log("Form submitted", formData);
};

Bonus: Use Formik or React Hook Form

They manage validation, errors, touched states, and form submission like a breeze.

npm install react-hook-form
const { register, handleSubmit, formState: { errors } } = useForm();

Interview tip: Show off your love for clean UX and preventing form spaghetti. Mention how you avoid code duplication and like to keep form logic modular.


3. What is lazy loading in React, and how does it improve application performance?

Lazy loading is React’s version of “don’t carry your whole closet if you only need your shoes.”

Instead of loading all components at once, we load them only when needed. This drastically improves initial load time.

import React, { Suspense, lazy } from 'react';
const HeavyComponent = lazy(() => import('./HeavyComponent'));

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

Why it’s great:

  • Faster page loads 📈
  • Better performance on slower devices 🐢
  • Helps split bundles intelligently 🧠

When interviewers ask this, drop terms like “code splitting,” “bundle optimization,” and “user-centric performance.”


4. How would you handle errors in a React app, and what is the role of error boundaries?

React apps crash. It happens. But how gracefully you handle it—that’s what matters.

Client-side errors

Use try/catch in async logic:

try {
  const data = await fetchSomething();
} catch (err) {
  setError(err.message);
}

UI errors

Enter: Error Boundaries. These are like bouncers that catch errors before they ruin the party.

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

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

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

Use it like:

<ErrorBoundary>
  <RiskyComponent />
</ErrorBoundary>

Mention in interviews that ErrorBoundary only catches render-time errors—not async or event handlers.


5. What are the benefits of server-side rendering (SSR) in React applications?

SSR = Supercharged SEO Results (okay, not officially, but it might as well be).

SSR means the page is rendered on the server and sent to the browser as fully-formed HTML. React can still hydrate it on the client.

Benefits:

  • Faster First Paint 🖼️
  • Better SEO 🚀
  • Good for sharing on social media (meta tags FTW)

Use Next.js for SSR:

npx create-next-app

Mention SSR is a trade-off: more server load, but better SEO. Know when it matters (e.g., blogs, eCommerce). And when it doesn’t (e.g., dashboards).


6. How do you handle styling in React components? Discuss different approaches.

Ah, styles. The never-ending debate. Here’s how to make peace:

1. Inline Styles

<div style={{ color: 'red' }}>Hello</div>

Fast and direct—but lacks pseudo-classes and media queries.

2. CSS Modules

import styles from './Button.module.css';
<button className={styles.primary}>Click</button>

Great for scoping CSS.

3. Styled-Components / Emotion

const Button = styled.button`
  background: hotpink;
  color: white;
`;

Component-level styles with full CSS support.

4. Tailwind CSS

Utility-first. Makes you feel like a CSS wizard. ✨

<button className="bg-blue-500 text-white p-2 rounded">Click Me</button>

Interview pro tip: Mention you pick styles based on project size, team, and maintainability.


7. How would you pass data between sibling components in React without using Redux?

You’ve got ComponentA and ComponentB, both children of ParentComponent. They need to talk.

Option 1: Lift State Up

Parent holds the state and passes props to both children.

function Parent() {
  const [data, setData] = useState('');
  return (
    <>
      <ComponentA setData={setData} />
      <ComponentB data={data} />
    </>
  );
}

Option 2: Context API

If state needs to go across multiple levels, Context saves the day.

const MyContext = createContext();

<MyContext.Provider value={value}>
  <ComponentA />
  <ComponentB />
</MyContext.Provider>

Use useContext inside both siblings.

Avoid Redux unless your app is a full-blown state monster.


8. Explain the use case of useEffect() for fetching data from an API

useEffect is your go-to hook for all things side-effect-y. Think of it as your Swiss Army knife for lifecycle control.

When you want to fetch data when a component mounts:

useEffect(() => {
  async function fetchData() {
    const res = await fetch('https://api.example.com/data');
    const json = await res.json();
    setData(json);
  }
  fetchData();
}, []);

It’s like saying, “Do this once the component is ready.”

Cleanup Example:

useEffect(() => {
  const interval = setInterval(() => console.log("Tick"), 1000);
  return () => clearInterval(interval);
}, []);

Interview hint: Talk about the dependency array like it’s the boss. It decides when useEffect runs. And yes, infinite loops are a thing – watch out!

9. How do you handle asynchronous operations in React using async/await or Promises?

Ah, async operations the bread and butter of any modern app. Whether you’re talking to an API, saving form data, or just pretending your app does something cool, asynchronous handling is essential.

✅ The Basics with useEffect and async/await

Here’s the classic combo:

useEffect(() => {
  const fetchData = async () => {
    try {
      const response = await fetch("https://api.example.com/data");
      const data = await response.json();
      setData(data);
    } catch (error) {
      console.error("Fetching failed:", error);
    }
  };

  fetchData();
}, []);

Now, notice a few things here:

  • We’re defining an inner async function because useEffect itself can’t be async (React will yell at you).
  • We gracefully catch errors using try/catch.
  • The dependency array [] ensures it runs only once when the component mounts.

🤝 Using Promises (Old School)

If you’re feeling retro or just trying to impress an interviewer:

useEffect(() => {
  fetch("https://api.example.com/data")
    .then(res => res.json())
    .then(data => setData(data))
    .catch(err => console.error("Oops!", err));
}, []);

🚀 Bonus Points

  • Talk about loading indicators (setLoading(true/false)) to enhance UX.
  • Mention state race conditions when setting state after unmount. Use flags or abort controllers.
  • Show you’re aware of async in event handlers too:
const handleClick = async () => {
  const result = await doSomethingAsync();
  console.log(result);
};

This shows you understand React’s flow and the JavaScript event loop. Basically, you’re not just coding—you’re orchestrating behavior.


10. How would you re-render a component when the window is resized?

Let’s face it—your app should be as responsive as your best friend replying to memes. And sometimes you need to know when the window resizes, so your UI can adapt.

🎣 Custom Hook with useEffect + useState

function useWindowSize() {
  const [size, setSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight,
  });

  useEffect(() => {
    const handleResize = () => {
      setSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    };

    window.addEventListener("resize", handleResize);
    return () => window.removeEventListener("resize", handleResize);
  }, []);

  return size;
}

Then in your component:

const { width, height } = useWindowSize();

return (
  <div>
    <p>Window size: {width} x {height}</p>
  </div>
);

Why this rocks in interviews:

  • It shows you know how to deal with side effects.
  • You clean up your event listeners like a pro (no memory leaks here, thank you).
  • Bonus: Say you debounce the resize event for better performance.
const handleResize = debounce(() => {
  setSize({ width: window.innerWidth, height: window.innerHeight });
}, 300);

And that’s it! You’re basically telling React, “Hey, watch the window and ping me when it changes.

Please don’t forget to leave a review

Leave a reply

Your email address will not be published. Required fields are marked *

Cookies Notice

Our website use cookies. If you continue to use this site we will assume that you are happy with this.