Skip to the solution
EasyFrontend6 min read

What are the advantages of using React over plain JavaScript?

808 views

The problem

Question presented to candidate: "We could build this UI with plain JavaScript and document.querySelector. Make the case for React β€” and be honest about what it costs."

What a strong answer should cover:

  • The central win: declarative rendering eliminates the class of bugs where the DOM and the data drift out of sync.
  • Componentisation β€” reusable units that own their own state and markup together.
  • Reconciliation β€” React computes the minimal DOM updates so you never hand-write them.
  • Ecosystem and hiring β€” routing, forms, data fetching, testing tools, and a large talent pool.
  • Cross-platform β€” the same component model targets native via React Native.
  • Honest costs: a build step, bundle size, a learning curve, and no advantage for genuinely simple pages.
  • Maturity signal: React is not automatically faster than hand-written DOM code; it trades a little raw speed for correctness and maintainability.

Clarifying questions expected:

  • "How complex is the UI β€” how much state is there, and how much of it is shared?"
  • "Is this a long-lived product with a team, or a one-off page?"

Code / implementation expected: Optional. A side-by-side of the same widget in both styles makes the argument faster than prose.

  • benefits
  • declarative
  • components
  • virtual dom

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

6 min read Β· 8 sections

Try it in the playground

Open any example in the playground to run and change it.

ReactThe same widget, imperative versus declarative, side by side
import { useState, useRef, useEffect } from "react";

// ── The imperative way, written the way plain JS forces you to ──────────────
// Every derived piece of UI needs its own explicit update. Miss one and the
// widget contradicts itself β€” and nothing tells you which line went stale.
function ImperativeCounter() {
  const rootRef = useRef(null);
  const scoreRef = useRef(0);

  useEffect(() => {
    const root = rootRef.current;
    root.innerHTML =
      '<p>Score: <b class="score">0</b></p>' +
      '<p class="status">untouched</p>' +
      '<p class="trophy" style="display:none;color:goldenrod">πŸ† three or more!</p>' +
      "<button>Score a goal</button>";

    const btn = root.querySelector("button");
    const onClick = () => {
      scoreRef.current += 1;
      const n = scoreRef.current;
      // Four separate, easily-forgotten DOM edits for ONE state change:
      root.querySelector(".score").textContent = String(n);
      root.querySelector(".status").textContent = n > 5 ? "getting high" : "counting";
      root.querySelector(".trophy").style.display = n >= 3 ? "block" : "none";
      btn.textContent = n >= 5 ? "Score another" : "Score a goal";
    };
    btn.addEventListener("click", onClick);
    return () => btn.removeEventListener("click", onClick);
  }, []);

  return <div ref={rootRef} />;
}

// ── The declarative way ────────────────────────────────────────────────────
// One state value. Every derived line follows from it automatically, so they
// cannot get out of step with each other.
function DeclarativeCounter() {
  const [score, setScore] = useState(0);

  return (
    <div>
      <p>Score: <b>{score}</b></p>
      <p>{score === 0 ? "untouched" : score > 5 ? "getting high" : "counting"}</p>
      {score >= 3 && <p style={{ color: "goldenrod" }}>πŸ† three or more!</p>}
      <button onClick={() => setScore((s) => s + 1)}>
        {score >= 5 ? "Score another" : "Score a goal"}
      </button>
    </div>
  );
}

export default function App() {
  const box = { border: "1px solid #ccc", borderRadius: 8, padding: 16, flex: 1 };
  return (
    <div style={{ padding: 24, fontFamily: "system-ui" }}>
      <div style={{ display: "flex", gap: 16 }}>
        <div style={box}><h4 style={{ marginTop: 0 }}>Imperative</h4><ImperativeCounter /></div>
        <div style={box}><h4 style={{ marginTop: 0 }}>Declarative</h4><DeclarativeCounter /></div>
      </div>
      <p style={{ color: "#666", fontSize: 13 }}>
        Both behave identically. The left one needs four explicit DOM edits per
        click; the right one derives all four from a single number.
      </p>
    </div>
  );
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 10 of 119 in React.js

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All React.js questions
Up nextEasy

How do you pass data between components in React?

Continue