The Problem with Vanilla JS
Both versions of our counter work, but look at the event handlers again. Every single one does two things:
- Updates the state (changes
count) - Calls
updateCounter()to re-render the display
What would happen if we forgot to call updateCounter() in one of the handlers? The count variable would change, but the screen would not reflect it. The UI would be out of sync with the state.
Why This Is a Problem
In a tiny counter app, remembering to call updateCounter() three times is not a big deal. But imagine a real application with dozens of pieces of state and hundreds of places where state changes. You would have to manually trigger re-renders everywhere, and missing even one would cause a bug.
In the early 2010s, this was a common problem in web development. As UIs got more complex, keeping everything in sync became difficult. Developers had to manually track which parts of the page needed updating and write code to update them whenever state changed.
UI as a Function of State
The UI should always be a direct reflection of the current state. Ideally, we would focus on the logic, capturing user interactions and updating state, and have the UI update automatically.
In other words:
Given some state, the UI is a predictable output of that state. When state changes, the UI should update automatically.
This is the core idea behind React and most modern UI frameworks.
React
React was built to solve exactly the problems we just encountered:
- HTML-like syntax in JavaScript: write UI that looks like HTML but is actually JavaScript, with syntax highlighting, auto-completion, and error checking
- Automatic re-rendering: when state changes, React re-renders the UI for you
- Component-based: break your UI into reusable, self-contained pieces
- Efficient updates: React figures out what actually changed and only updates those parts of the DOM
React is a JavaScript library to build user interfaces. It is a package you add to your project, like any npm package. It runs on the client side — in the browser.
You need a build tool (like Vite) to bundle your React code into plain JavaScript that the browser can run. Vite also transforms JSX (the HTML-like syntax which we will see shortly) into regular JavaScript function calls. When you create a Vite project with the React template, it sets all of this up for you.
History of React
React was created by Jordan Walke, a software engineer at Facebook, to solve a specific problem: keeping complex UIs in sync with changing data. Facebook’s notification system and news feed were getting hard to maintain. When data changed, someone had to manually update every affected part of the page, and that led to bugs and inconsistencies.
Walke’s approach was to let developers describe what the UI should look like for a given state, and let the library figure out how to update the page efficiently. Instead of writing imperative code like “find this element, change its text, add this class,” you write a function that returns the UI you want, and React does the rest.
React was first used internally at Facebook in 2011, then deployed on Instagram in 2012, and open-sourced in May 2013. Many developers were skeptical at first, because mixing HTML-like syntax (JSX) into JavaScript felt wrong to them. But as teams started using it, the component model and one-way data flow turned out to work well for building and maintaining large applications.
Today, React is one of the most widely used frontend libraries. Its core ideas have influenced nearly every modern frontend framework: components, declarative rendering, and state-driven UI.
In the next section, we will rebuild our counter in React.