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!

DOM Manipulation: In-Depth Explanation

DefinitionDOM manipulation** refers to the process modifying the structure, content, style, or behavior page using JavaScript. The Document Object Model (DOM) is a programming interface for HTML/XML represents the page as a tree of objects. By with this tree, developers can add, remove, or modify update text/content, ** styles, and handle user interactions in real-time.


Core Concepts & Key Points

1. The DOM Tree Structure

  • The DOM models a webpage as a hierarchical tree where each HTML element is a node.
  • Nodes can be elements (<div>, <p>), text nodes ("Hello World"), attributes (class="container"), or comments.
  • Example structure:
    Document
      └── <body>
          ├── <header>
          │   └── <nav>...</nav>
          └── <main>
              └── <p id="target">Dynamic Content</p>
    

2. Common DOM Manipulation Methods

MethodPurposeExample
document.getElementById()Selects an element by its id attributeconst el = document.getElementById('header');
document.querySelector()Selects the first element matching a CSS selectorconst btn = document.querySelector('.btn-primary');
element.querySelectorAll()Returns all elements matching a CSS selectorconst links = document.querySelectorAll('a');
element.createElement()Creates a new HTML elementconst newDiv = document.createElement('div');
element.appendChild()Adds a node as the last child of an elementdiv.appendChild(newDiv);
element.removeChild()Removes a child node from an elementdiv.removeChild(oldDiv);
element.classListToggles, adds, or removes CSS classesbtn.classList.add('active');
element.styleDirectly modifies inline CSS stylesel.style.backgroundColor = 'red';
element.setAttribute()Sets or updates an HTML attributeimg.setAttribute('src', 'image.jpg');
element.textContentGets or sets the text content of an element (ignores HTML tags)para.textContent = 'Hello';
element.innerHTMLGets or sets HTML content (allows HTML injection)div.innerHTML = '<span>Bold</span>';
element.addEventListener()Attaches an event listener (e.g., clicks, keypresses)btn.addEventListener('click', handleClick);

3. Event Handling

  • Events (e.g., click, keypress, submit) trigger functions when user interactions occur.
  • Best Practice: Always clean up event listeners with removeEventListener to avoid memory leaks.

Example: Event Handling

const button = document.getElementById('myBtn');

function handleClick() {
  alert('Button clicked!');
}

// Add listener
button.addEventListener('click', handleClick);

// Remove listener (cleanup)
button.removeEventListener('click', handleClick);

4. Performance Considerations

Direct DOM manipulation is expensive because each change can trigger reflows (redesigning the page layout) and repaints (redrawing CSS/visual changes). Follow these rules to optimize:

  1. Batch Changes
    Modify multiple elements in a single frame instead of one-by-one.
  2. Use requestAnimationFrame()
    Synchronize animations with the browser’s refresh rate for smooth rendering.
  3. Avoid Layout Thrashing
    Read layout properties (offsetHeight, clientWidth) before making changes and after changes.
    Example:
    // Bad: Read + write pattern (causes layout thrashing)
    const height = div.offsetHeight;
    div.style.height = '500px';
    
    // Good: Batch writes
    div.style.height = '500px';
    
  4. Use Document Fragments
    Build large DOM trees off-screen first, then insert them into the main document in one operation.

Document Fragment Example

const fragment = document.createDocumentFragment();

for (let i = 0; i < 100; i++) {
  const p = document.createElement('p');
  p.textContent = `Item ${i}`;
  fragment.appendChild(p);
}

document.body.appendChild(fragment); // Single DOM operation

5. React vs. Vanilla DOM Manipulation

AspectVanilla JavaScriptReact
ApproachImperative: Manually update the DOMDeclarative: Define what the UI should look like; React handles the how
UpdatesDirect manipulation (e.g., element.textContent = '...')Re-render components based on state/props changes
PerformanceRisk of inefficient updatesVirtual DOM diffing optimizes updates
Event HandlingaddEventListener attached to DOM elementsSynthetic event system (onClick, onChange) wrapped by React
State ManagementManual (e.g., storing data in variables)Built-in state hooks (useState, useReducer)

Example: React’s Declarative Approach

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

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

React automatically updates the DOM when count changes—no manual DOM manipulation required.


Common Interview Questions (Related to DOM Manipulation)

1. How does the browser parse and render the DOM? What triggers a reflow/repaint?

  • Answer:
    • Parsing: HTML is parsed into a DOM tree, CSS into a CSSOM tree. These combine to form the render tree.
    • Reflow: Occurs when the browser recalculates element positions/sizes (e.g., changing width, padding).
    • Repaint: Redraws visible parts of the page (e.g., changing backgroundColor).
      Trigger Examples:
    • offsetHeight, getBoundingClientRect() → force reflow.
    • Changing style properties → repaint.

2. Explain the difference between innerHTML, textContent, and innerText.

  • Answer:
    • innerHTML: Parses and inserts HTML strings (Potentially unsafe due to XSS).
      element.innerHTML = '<img src="x">';
    • textContent: Sets raw text (ignores HTML tags). Fast and safe.
      element.textContent = '<img src="x">'; → renders as plaintext.
    • innerText: Returns rendered visible text (respects CSS display:none).
      Good for accessibility reading.

3. Why should you avoid using innerHTML for dynamic updates?

  • Answer:
    • Security Risk: Allows XSS attacks if untrusted data is inserted.
    • Performance: Triggers full re-parsing of the HTML substring.
    • Loss of Event Listeners: Existing event handlers are removed when innerHTML overwrites content.
      Alternatives: Use textContent, createElement, or React’s JSX rendering.

Best Practices Summary

  1. Prefer textContent over innerHTML for text-only updates (security + performance).
  2. Batch DOM changes using document fragments or requestAnimationFrame.
  3. Use CSS classes instead of inline styles for dynamic styling (easier maintenance).
  4. In React, rely on state/props—avoid manual DOM queries (document.getElementById) unless absolutely necessary (e.g., integrating third-party libraries).
  5. Profile performance with browser dev tools (Performance tab) to identify expensive DOM operations.

Tip: Always ask clarifying questions during interviews about constraints (e.g., "Is this a React app or vanilla JS?") before diving into solutions.

</details>

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