What is React? Declarative vs imperative

Acadestine

What is React? Declarative vs Imperative

React is a JavaScript library for building user interfaces. It was created by Facebook and has become one of the most popular frontend libraries in the world. But what makes React special? At its core, React embraces a declarative programming paradigm, which is a fundamental shift from the traditional imperative approach.


React is a component-based library that allows you to build encapsulated, reusable pieces of UI. It manages the view layer of your application and efficiently updates and renders components when data changes.

Key Features of React

  • Component-Based – Build encapsulated components that manage their own state.
  • Declarative – Describe what the UI should look like, and React handles the updates.
  • Virtual DOM – Efficiently updates the real DOM by comparing changes.
  • Unidirectional Data Flow – Data flows from parent to child components.
  • JSX – A syntax extension that allows you to write HTML-like code in JavaScript.

React is a library, not a framework. It focuses only on the UI layer, allowing you to choose other libraries for routing, state management, and HTTP requests.


The distinction between declarative and imperative programming is fundamental to understanding React.

Imperative Programming

Imperative programming describes how to achieve a result. You write step‑by‑step instructions that specify exactly what the computer should do.

Analogy: Giving someone directions like "Turn left at the traffic light, drive 200 meters, then turn right."

Example – Imperative DOM Manipulation

// Imperative approach to updating a UI
const div = document.getElementById('container');
div.innerHTML = ''; // Clear it
const newDiv = document.createElement('div');
newDiv.textContent = 'Hello, World!';
newDiv.className = 'greeting';
div.appendChild(newDiv);
// You're telling the browser EXACTLY what steps to perform

Declarative Programming

Declarative programming describes what you want to achieve, without specifying the steps to get there. You declare the desired state, and the system figures out how to achieve it.

Analogy: Saying "I want to go to the airport" and letting the GPS figure out the route.

Example – Declarative with React

// Declarative approach with React
function Greeting({ name }) {
  return (
    <div className="greeting">
      Hello, {name}!
    </div>
  );
}
// You describe WHAT the UI should look like for a given state.
// React handles the HOW (rendering, updating, etc.).
Analogy – Building a House
  • Imperative – You tell the builders exactly where to place every brick, nail, and pipe.
  • Declarative – You give the builders a blueprint, and they figure out the steps.

React is declarative because you describe what the UI should look like for any given state, and React automatically updates the DOM to match that description.

Thinking Declaratively

Instead of manually manipulating the DOM, you:

  1. Define components that return a UI description (using JSX).
  2. Manage state that changes over time.
  3. React reconciles the difference between the virtual DOM and the real DOM.
// Declarative React component
function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}
// You don't tell React HOW to update the DOM.
// You tell it WHAT the UI should look like based on `count`.
// React handles the rest!

Virtual DOM – The Engine Behind Declarative Updates

React creates a virtual DOM (a lightweight JavaScript representation of the actual DOM). When state changes: 1. React creates a new virtual DOM tree. 2. It compares the new tree with the previous one (diffing). 3. It efficiently updates only the parts of the real DOM that changed (reconciliation).

This is what makes React's declarative approach performant.

You don't need to worry about the Virtual DOM internals. Just focus on describing the UI, and React handles performance optimization.


Let's compare imperative and declarative approaches side‑by‑side for a common task: showing/hiding an element.

Imperative Approach (Vanilla JS)

// You tell the DOM exactly what to do
function toggleVisibility() {
  const element = document.getElementById('myElement');
  if (element.style.display === 'none') {
    element.style.display = 'block';
  } else {
    element.style.display = 'none';
  }
}
// Step-by-step instructions to manipulate the DOM

Declarative Approach (React)

// You declare what the UI should be based on state
function Toggle() {
  const [isVisible, setIsVisible] = useState(true);

  return (
    <div>
      {isVisible && <div id="myElement">I am visible!</div>}
      <button onClick={() => setIsVisible(!isVisible)}>
        Toggle
      </button>
    </div>
  );
}
// You describe the UI for each state.
// React manages the DOM updates.

In React: Changes to state trigger re‑renders, and React figures out the most efficient way to update the DOM.


Declarative programming offers several advantages for building UIs:

  • Predictability – The UI is a function of state. For a given state, the UI is always the same.
  • Reduced Bugs – No manual DOM manipulation means fewer opportunities for bugs.
  • Maintainability – Components are easier to understand and debug.
  • Reusability – Components can be reused in different contexts.
  • Testability – You can test components by providing props and checking the rendered output.

Real‑World Impact

In large applications, the declarative approach dramatically reduces complexity. You don't need to track which DOM nodes were updated when; you just manage state and let React handle the rest.

// Declarative code is easier to reason about
function UserList({ users, filter }) {
  const filteredUsers = users.filter(user => 
    user.name.toLowerCase().includes(filter.toLowerCase())
  );

  return (
    <ul>
      {filteredUsers.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}
// No DOM manipulation! Just pure JavaScript and JSX.

While React is primarily declarative, there are rare situations where you might use imperative code:

  • Focus management – Using refs to focus an input.
  • Animations – Triggering animations imperatively.
  • Third‑party libraries – Integrating non‑React libraries (e.g., D3, Chart.js).

React provides refs and lifecycle methods to handle these imperative needs.

function InputWithFocus() {
  const inputRef = useRef(null);

  const focusInput = () => {
    // Imperative DOM manipulation – but contained
    inputRef.current?.focus();
  };

  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={focusInput}>Focus Input</button>
    </div>
  );
}

Best Practice: Keep imperative code isolated. When you need to use imperative patterns, encapsulate them in custom hooks or components.


  • React is a declarative, component‑based library for building UIs.
  • Imperative programming = how to achieve something (step‑by‑step instructions).
  • Declarative programming = what you want to achieve (describe the desired state).
  • React's declarative approach makes UI development more predictable, maintainable, and bug‑free.
  • React uses the Virtual DOM to efficiently update the real DOM based on state changes.
  • While React is declarative, you can still use imperative code sparingly via refs.
Key Takeaway

"React lets you describe what the UI should look like, not how to make it look that way. This paradigm shift is what makes React so powerful and developer‑friendly."

Happy coding!

Previous Lesson Next Lesson