When I first started with React, the landscape was vastly different from what we have today. React was already a game-changer, but the tools and best practices were constantly evolving. Over the years, I’ve seen major shifts—from Create React App (CRA) to Next.js, class components to hooks, Redux to Zustand, and React Router to TanStack Router. Each phase brought challenges, excitement, and a lot of learning.
This blog is a reflection of my journey through the evolving React ecosystem and how modern React apps are built today.
The Early Days: Create React App & The React Router Struggles
Back in my early days, Create React App (CRA) was the go-to tool for bootstrapping a React project. It provided a simple setup with Webpack and Babel pre-configured, making it easy for beginners to dive in. I still remember my first React app, where I used:
Material UI for styling
React Router v6 for navigation
Redux for state management
React Router v5 was the standard, but then came React Router v5 with a completely new API. I vividly recall the migration struggles—routes had to be restructured, and breaking changes forced us to rethink navigation strategies. Documented them here.
At the same time, managing state with Redux was a norm, but it came with boilerplate-heavy actions, reducers, and store configurations. Even for a simple counter app, you had to write multiple files! Still, at that time, Redux was the best choice for global state management.
The Next.js Era: Embracing Server-Side Rendering
As React applications grew, performance and SEO became critical. Enter Next.js. My transition from CRA to Next.js felt like moving from a tiny apartment to a fully furnished house.
With Next.js, I could:
Use server-side rendering (SSR) with
getServerSideProps
Generate static pages (SSG) with
getStaticProps
Leverage API routes for backend functionalities
These features were game-changers. I remember working on client’s SEO-heavy project where SSR drastically improved our rankings for thier real estate marketing. The idea of fetching data server-side before rendering felt revolutionary at the time.
The Evolution: From Pages Router to App Router
For years, Next.js relied on the Pages Router, where each .jsx
or .tsx
file inside the pages/
directory automatically became a route. It was simple and effective. Need a new page? Just add a new file inside pages/
, and it worked like magic.
However, this approach had limitations:
Data fetching was explicit (
getServerSideProps
,getStaticProps
,getInitialProps
)Mixing API routes and frontend logic felt disconnected
Routing wasn’t as flexible (deep nested routes required workarounds) and a layout convention was not really available
The App Router Mental Model
With improvements in Next.js 13+, the App Router introduced a more intuitive mental model:
Each folder inside the
app/
directory represents a routeA
page.tsx
file defines the frontend component of that routeA
route.ts
file inside anapi/
subfolder defines the backend route for that page
The Rise of Modern Ecosystem Tools
Beyond Next.js, the React ecosystem has been evolving at an incredible pace. Some of the most notable shifts I’ve experienced include:
1. React Query & The Death of Global State for Data Fetching
Earlier, Redux was used for everything—including async data fetching. But then React Query (TanStack Query) came along and changed the game.
With React Query, I no longer had to manually handle caching, re-fetching, loading states or managing Infinite Queries. It felt like magic. Today, I can’t imagine building a React app without it.
2. From Redux to Lighter State Management
For years, Redux was the default choice, but with time, developers sought simpler alternatives like:
Zustand (lightweight and minimal)
Jotai (atomic state management)
XState (state machines)
I remember a project where Redux felt like overkill, so I switched to Zustand, and suddenly, managing state became effortless. No actions, no reducers—just a simple store and hooks.
3. React Router vs. TanStack Router
When setting up frontend apps without frameworks React Router has always been a staple, but recently, TanStack Router has emerged as a strong competitor with the goodness of typed routes and when combining the power of Query it becomes really powerfull as a client side routing solution. It provides better type safety, parallel routes, and data-aware navigation. I’m excited to see how these routing libraries in React evolves further.
4. The Fall of CSS-in-JS & The Rise of Tailwind
A few years ago, CSS-in-JS solutions like Styled Components and Emotion were the go-to choices. I used them extensively, but they had drawbacks—runtime performance issues and large bundle sizes.
Then Tailwind CSS came along. Initially, I was skeptical about writing classes like text-gray-500
instead of CSS, but once I got the hang of it, the benefits were undeniable. Faster styling, better DX, and lower CSS bloat. And introduction to headless UI libraries like Headless UI, Radix UI, React Aria Components have started becomming the norm. And shadcn ui becoming increasingly promising with its reusable copy paste components!
The Present & Future of React
Looking at React today, it’s clear we’ve come a long way:
React Server Components are the new norm
Next.js is becoming the default meta-framework
State management is now lightweight and modular
The ecosystem is shifting towards performance and developer experience
As I reflect on my journey, I realize how exciting it is to be a React developer. The ecosystem is constantly evolving, and there’s always something new to learn. The best part? React’s core philosophy remains the same—building powerful UIs with components.
What’s next for React? Only time will tell, but one thing is certain: it’s an exciting time to be a React developer.