A few weeks ago, I set up an experiment for myself:
Could I learn React while building without turning the process into
AI-assisted copy-pasting?
The rule was simple:
- Learn the overview of a concept first.
- Attempt the feature myself.
- Only ask AI for a hint after getting genuinely stuck.
- Follow a pre-planned concept sequence instead of randomly jumping between topics.
I said I'd test it for a few weeks and switch to a structured course if
it wasn't producing real understanding.
Verdict so far: it's holding up.
This week was React Router, and I reached a point I care about more than
simply getting the code working:
I can explain why the pieces exist and how they fit together.
My initial assumption about routing
Going in, I assumed routing would mean more setup and friction than
using normal HTML links.
It turned out to be almost the opposite.
A normal <a> tag tells the browser to navigate to another document,
which causes a full page load. In a React Single Page Application, we
generally want navigation to happen on the client so the app can change
what it renders without loading an entirely new document.
That's where React Router comes in.
The basic pieces started making sense once I understood their jobs:
-
BrowserRouter--- provides the routing context for the application. -
Routes--- contains the routes the application knows about. -
Route--- maps a URL pattern to what should be rendered. -
Link--- provides client-side navigation rather than relying on a normal document navigation.
So the API stopped feeling like arbitrary React Router ceremony.
Each piece had a reason for being there.
The first thing that really clicked: dynamic routes
I practiced this by building a small blog.
The blog had a list of posts, and clicking a post took me to something
like:
/blog/42
Instead of creating a separate route for every possible post, I could
define a dynamic route:
/blog/:id
Then useParams() gives the component the value from that dynamic part
of the URL.
So:
/blog/42
becomes something conceptually like:
{ id: "42" }
I could then use that ID to find the corresponding post and render it.
That was a useful shift in understanding.
The URL wasn't just a destination anymore.
It could carry information that the application uses to decide what to
render.
Nested routes + Outlet
Nested routing was another one that clicked once I saw the relationship
between the parent and child routes.
For example, imagine a dashboard with:
/dashboard
/dashboard/profile
/dashboard/settings
The dashboard can provide the shared layout, while the child route gets
rendered into the location provided by Outlet.
Conceptually:
Dashboard
├── shared navigation
├── shared layout
│
└── <Outlet />
↓
Profile / Settings
That made much more sense to me than thinking of every route as
completely separate pages.
Protected routes --- mental model only
This is one area where I'm deliberately not pretending I've
implemented more than I have.
I haven't built authentication yet.
What I did understand was the basic routing mental model: a protected
page such as a dashboard can have a condition that determines whether
the user should be allowed to see it.
Conceptually:
/dashboard
↓
┌─────────────┐
│ Auth check │
└─────────────┘
↓ ↓
YES NO
↓ ↓
Dashboard Login
That's the level I reached this week.
And there's an important distinction I'll need to go deeper into when I
actually learn authentication:
A frontend route guard controls what the user can access in the UI; it
isn't, by itself, a security boundary. Actual authorization needs to
be enforced by the backend/server as well.
For now, I'm happy with understanding the routing side of the mental
model.
The bigger lesson wasn't actually routing
The more interesting result from this week wasn't learning useParams,
Outlet, or Link individually.
It was seeing the learning method work.
I'm not trying to collect React APIs just so I can say I've used them.
I'm trying to reach the point where, when I see a piece of React code, I
can explain:
Why is this here?
What problem does it solve?
How does it connect to the rest of the application?
With React Router, I'm starting to get there.
So the experiment continues.
Next stop: custom hooks.
Top comments (1)
Using
/blog/:idto choose a post andOutletto preserve the dashboard layout gives you two concrete things to explain without reciting API definitions. I'd extend your experiment by deciding what the blog should show for an ID that doesn't exist, then implementing that behavior before asking AI for a hint. A missing-post screen with a way back to the list is a small feature, but deciding where it belongs tests both your routing model and how readers recover when something goes wrong.