javascript and react and dom

Intermediate

Overview

JavaScript, DOM form the cornerstone of modern front-end development interviews. This combination tests candidates' understanding of client-side logic, component-based architecture, and direct manipulation of the browser environment. These topics are commonly evaluated at intermediate levels companies ranging from startups giants like Amazon, Google, and Facebook as they reflect real-world application development skills.


Core Concepts

JavaScript Fundamentals

Definition

JavaScript is a high-level, dynamic programming language primarily used for web development to create interactive, client-side applications.

Key Points

  • First-class functions: Functions are treated as objects and can be passed as arguments, returned from other functions, and assigned to variables.
  • Closure: Functions retain access to the scope in which they were created, even after that outer function has finished executing.
  • Event Loop: JavaScript is single-threaded but uses an event loop (with call stack, callback queue, and microtask queue) to handle asynchronous operations.
  • Prototype Chain: Inheritance is achieved through prototypal links between objects.

Example

// Closure example
function outer() {
  let count = 0;
  return function inner() {
    count++;
    return count;
  };
}

const increment = outer();
console.log(increment()); // 1
console.log(increment()); // 2

React Core Principles

Definition

React is a JavaScript library for building user interfaces, emphasizing component-based architecture and declarative UI.

Key Points

  • JSX: Syntax extension that lets you write HTML-like code in JavaScript.
  • State and Props: State manages internal component data; props pass data from parent to child components.
  • Virtual DOM: React uses a virtual representation of the DOM to optimize updates and minimize reflows.
  • Hooks: Functions (useState, useEffect, etc.) that enable state and side effects in functional components.

Example

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

function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  }, [count]); // Dependency array

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

DOM Manipulation

Definition

The Document Object Model (DOM) is a programming interface for HTML and XML documents. It represents the page so programs can alter the document structure, style, and content.

Key Points

  • Manipulation Methods: querySelector(), createElement(), appendChild(), classList, etc.
  • Event Handling: Attach listeners with addEventListener() and manage events like clicks, keyboard input.
  • Performance Considerations: Direct DOM operations are expensive; batch changes and use document fragments where possible.
  • React vs. Vanilla DOM: React abstracts DOM manipulation via reconciliation and virtual DOM for efficiency.

Example

// Vanilla DOM example: Toggle a class on click
const button = document.querySelector('#toggleBtn');
const element = document.getElementById('target');

button.addEventListener('click', () => {
  element.classList.toggle('highlight');
});

Common Interview Questions

  1. Explain how closures work in JavaScript and provide a practical use case.

    • Answer:
      A closure gives an inner function access to the scope of an outer function, even after the outer function has executed.
      Use case: Data privacy (e.g., module pattern) or maintaining state in async callbacks.
      function createCounter() {
        let count = 0;
        return {
          increment: () => ++count,
          getValue: () => count
        };
      }
      const counter = createCounter();
      console.log(counter.getValue()); // 0
      counter.increment();
      console.log(counter.getValue()); // 1
      
  2. What is the purpose of the useEffect hook in React? How would you handle side effects and dependencies?

    • Answer:
      useEffect performs side effects in functional components (e.g., data fetching, subscriptions).
      • Syntax: useEffect(callback, dependencies)
      • Empty array []: Run once after initial render.
      • No dependencies: Run after every render.
      • Dependency array [dep]: Re-run when dep changes.
      useEffect(() => {
        fetchData(props.userId);
        return () => { /* Cleanup (e.g., unsubscribe) */ };
      }, [props.userId]); // Only re-run if userId changes
      
  3. How does React’s reconciliation algorithm work? What factors determine whether an element is updated?

    • Answer:
      Reconciliation compares the virtual DOM tree with the previous tree using a diffing algorithm.
      • Key factors:
        • Element type changes (e.g., <div><span>) trigger rebuilds.
        • Keys help identify list items across renders.
        • Component state/props changes trigger updates.
          React updates only components where changes are detected, minimizing actual DOM manipulation.
  4. What are the differences between controlled and uncontrolled components in React?

    • Answer:
      • Controlled components: Form data is managed by React state (defaultValuevalue).
      • Uncontrolled components: Data is managed by the DOM node (defaultValue only; access via ref).
      // Controlled
      function Input() {
        const [value, setValue] = useState('');
        return <input value={value} onChange={e => setValue(e.target.value)} />;
      }
      
      // Uncontrolled
      function Input() {
        const inputRef = useRef(null);
        return <input defaultValue="Initial" ref={inputRef} />;
      }
      
  5. Why is direct DOM manipulation discouraged in React? What are the alternatives?

    • Answer:
      Direct DOM manipulation bypasses React’s virtual DOM, breaking the diffing algorithm and causing performance issues or bugs.
      Alternatives:
      • Use state to trigger updates.
      • Leverage refs for reading values (not mutating).
      • Use ports/portal (ReactDOM.createPortal) for modals/overlays.

Detailed Examples

Example 1: Building a Custom Hook for API Calls

Scenario

Create a useFetch hook that handles data fetching, loading states, and errors.

Solution Code

import { useState, useEffect } from 'react';

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(url);
        if (!response.ok) throw new Error('Network response was not ok');
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]);

  return { data, loading, error };
}

// Usage in component
function UserProfile({ userId }) {
  const { data, loading, error } = useFetch(`https://api.example.com/users/${userId}`);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error}</p>;

  return <div>{data.name}</div>;
}

Explanation

  1. State Management: Uses useState for data, loading, and error states.
  2. Effect Hook: Fetches data when url changes (dependency array).
  3. Cleanup: None needed here, but could abort fetch requests on unmount.
  4. Reusability: Hook can be used across components needing API calls.

Example 2: Optimizing DOM Updates with requestAnimationFrame

Scenario

Animate a ball’s position smoothly without jitter.

Solution Code

function animateBall() {
  const ball = document.getElementById('ball');
  let position = 0;

  function update() {
    position += 1;
    ball.style.left = `${position}px`;

    if (position < window.innerWidth - 50) { // Stop before edge
      requestAnimationFrame(update);
    }
  }

  update();
}

// Trigger animation on button click
document.getElementById('startBtn').addEventListener('click', animateBall);

Explanation

  • requestAnimationFrame: Schedules updates before the next repaint, ensuring smooth animation.
  • Batching: Moves the ball in a single frame rather than multiple costly DOM changes.
  • Performance: Avoids layout thrashing by synchronizing with the browser’s refresh rate.

Practice Problems

  1. Easy: Explain the output of the following closure code:

    function test() {
      let count = 0;
      return function() { return ++count; };
    }
    const t = test();
    console.log(t());
    console.log(t());
    

    Hint: Understand how lexical scoping and closure retain access to count.

  2. Medium: Implement a React component that fetches and displays a random joke from an API, with error handling and a refresh button.

    Hint: Use useEffect, useState, and useRef for cleanup/abort controller.

  3. Intermediate: Build a vanilla JS function that efficiently adds thousand separators to a numeric string (e.g., 12345671,234,567) without using toLocaleString().

    Hint: Use regular expressions or string manipulation in reverse.


Key Takeaways

  • Master Closures: They’re fundamental to JavaScript patterns and often tested in interviews.
  • Understand React’s Data Flow: State → render → effect → update cycle.
  • Optimize DOM Interactions: Prefer React’s declarative approach; use requestAnimationFrame for animations.
  • Practice Hook Usage: Focus on dependency arrays, cleanup functions, and custom hooks.
  • Common Pitfalls:
    • Stale closures in effects (use functional updates: setCount(prev => prev + 1)).
    • Forgetting dependency arrays in useEffect (causes infinite loops).
    • Overusing indexes as keys in lists (breaks reordering performance).

Study Tip: Implement the practice problems manually, then compare your solution with optimized versions. Focus on readability and edge cases!

Ready for a new challenge?

Start a new session to explore different topics or increase the difficulty level.

Start New Session
javascript and react and dom Preparation Guide | Interview Preparation