The jQuery Era (2000-2012)
My first real web project was a form with client-side validation in 1999. I wrote DOM manipulation in vanilla JavaScript—absolutely painful. Every browser needed workarounds. IE 5 didn't support getElementById. Netscape and Internet Explorer had entirely different event models. CSS float layouts required careful management.
Then jQuery arrived in 2006, and the web changed overnight.
// Before jQuery: checking checkboxes
function toggleAll() {
var checkboxes = document.getElementsByTagName('input');
for (var i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type === 'checkbox') {
checkboxes[i].checked = !checkboxes[i].checked;
}
}
}
// jQuery made it this:
$('input[type=checkbox]').prop('checked', function() {
return !this.checked;
});
For the first time, JavaScript felt productive. The API was generous—sometimes three different ways to do the same thing. There was a "jQuery way" and everyone followed it. You selected elements, chained methods, and magic happened.
The community built on this: you learned jQuery plugins, mastered CSS selectors, and could build animated, interactive websites faster than ever before.
The Problem jQuery Couldn't Solve
But jQuery had a fundamental limitation: it didn't separate data from presentation. When you toggled a checkbox with jQuery, you were mutating the DOM directly. This worked fine for simple interactions. It broke apart at scale.
By 2012, single-page applications became viable. Gmail, Google Maps, and Facebook showed that rich web apps could compete with native applications. But managing state across 10,000 lines of jQuery event handlers was a nightmare.
The problem: jQuery made it too easy to couple UI to data. A checkbox's appearance was stored in the DOM. A list's items were stored as DOM nodes. When you needed to update them, you re-rendered manually: find the element, change its class, update its text. This duplicated your business logic across three different representations (the data, the DOM, your mental model of it).
Enter Angular (2010-2016)
Angular was the first serious attempt to fix this. The idea: templates bind directly to a data model. When data changed, the template updated automatically. When the user interacted with the template, the data model updated. Two-way binding.
// Angular 1: two-way binding magic
app.controller('CheckboxCtrl', function($scope) {
$scope.items = [{checked: true}, {checked: false}];
$scope.toggleAll = function() {
$scope.items.forEach(function(item) {
item.checked = !item.checked;
});
};
});
// The template:
// <input ng-repeat="item in items" ng-model="item.checked" />
// <button ng-click="toggleAll()">Toggle All</button>
This was revolutionary. You no longer needed to manipulate the DOM manually. Angular's digest cycle would figure it out. It felt automatic.
The problem: the digest cycle was a black box. If something wasn't updating, you had to debug the Angular framework itself. Performance was hard to predict. Two-way binding seemed great until you had 500 form fields fighting over who updated what.
React and the Paradigm Shift (2013-Present)
React's innovation was simple: forget about updating. Throw away the UI and rebuild it from scratch every time anything changes.
This sounds insane—rebuilding the entire DOM on every state change? But React's key insight was the virtual DOM. You don't actually touch the browser's DOM. You render to an in-memory representation, diff it against what was previously rendered, and only apply the minimal changes to the real DOM.
// React: declarative, unidirectional
function CheckboxList() {
const [items, setItems] = useState([
{id: 1, checked: true},
{id: 2, checked: false},
]);
const toggleAll = () => {
setItems(items.map(item => ({
...item,
checked: !item.checked
})));
};
return (
<>
{items.map(item => (
<input
key={item.id}
type="checkbox"
checked={item.checked}
/>
))}
<button onClick={toggleAll}>Toggle All</button>
</>
);
}
The elegance: your component is a pure function of its state. Given the same state, it always renders the same output. No black-box framework magic. The data flow is explicit and unidirectional: user action → state change → re-render.
This made reasoning about code dramatically easier. No more hunting through event handlers trying to figure out how state changes propagated. The entire flow was right there in the component.
The Web Components Episode (2015-2020)
In the middle of React's rise, the web platform tried to solve this natively with Web Components. Custom elements, shadow DOM, and HTML templates built into the browser.
The theory was perfect: you wouldn't need React anymore. The browser would give you componentization for free.
But Web Components had limitations. Shadow DOM broke styling. Custom elements didn't integrate well with existing form APIs. The ecosystem fragmented. React integrated better with the JavaScript tooling that was already dominant.
Where We Are Now (2024)
Today, React dominates not because it's perfect, but because:
- It made component composition natural
- The JSX syntax is genuinely better than templates
- The unidirectional data flow prevents entire classes of bugs
- The ecosystem is stable
But there are cracks. React is heavy (about 150kb). Server-side rendering is complex. The mental model breaks down for streaming and incremental updates.
New frameworks are emerging—Solid, Vue, Svelte—that take React's insights and simplify. They generate less JavaScript. They handle reactivity differently. They feel lighter.
What Comes Next
I suspect the future isn't a single framework. I think it's:
- Islands architecture: mostly static HTML with JavaScript sprinkled in
- Signals instead of virtual DOM: fine-grained reactivity where only what changed updates
- Better platform integration: browsers finally learning from React what developers want
- Less JavaScript: modern networks and CPUs are fast enough that shipping less code beats shipping faster code
But the core insight is here to stay: code should declare what the UI looks like given some state, not imperative instructions for how to change it. That's not React-specific. That's the future of the web.
Twenty years ago, jQuery made the web possible. React made it sane. Whatever comes next will build on both.