close up view of a code project in a text editor

Building My First React App Without Starting From Scratch — A Realistic Beginner’s Workflow

close up view of a code project in a text editor

Building My First React App Without Starting From Scratch — A Realistic Beginner’s Workflow

Most React tutorials begin with a sacred ritual:

“Create a new project in an empty folder.”

But what if you already have something that works? What if you’ve spent hours building a vanilla JavaScript app that fetches JSON, renders a table, and filters data — and you don’t want to delete it just to “do things the React way”?

I didn’t either. So I archived my old files instead of trashing them. And in doing so, I built my first real React app — not as a textbook exercise, but as a practical evolution of something I’d already made.

This is how I did it, what confused me, and why your learning path doesn’t need to match the tutorial script.


From Global Variables to useState: What Actually Changed?

In my vanilla JS version, I had:

js

It worked, but the UI and data were loosely connected. In React, I replaced that with two pieces of state:

js

And instead of manually updating the DOM, I let React re-render the table whenever either value changed.

The magic isn’t in the syntax — it’s in the mental model shift:

text

Your interface is a pure function of your application state.

No more innerHTML = "". No more appendChild. Just declare what the table should look like given the current data.


The One JSON Quirk That Tripped Me Up

My JSON structure looked like this:

json

Notice: title and authors are nested inside book.

In my first render attempt, I wrote:

js

…because the real path is reading.book.title.

Similarly, authors is an array, so I needed:

js

💡 Debugging tip: Log one item early:

js

This saves 20 minutes of guessing.


Filtering Without Overcomplicating Things

I wanted a dropdown to show “All”, “Reading”, “Finished”, etc.

Instead of storing filtered results in state (a common beginner mistake), I derived them on every render:

js

Why is this better?

  • ✅ Less state to manage

  • ✅ Always in sync with the source data

  • ✅ Zero performance cost for small datasets (<1000 items)

You don’t need useMemo here. Premature optimization is the enemy of clarity.

Then I passed filteredReadings to my <BookTable> component — clean, simple, and testable.


Common Pitfalls Checklist (From My Own Mistakes)

Here’s what went wrong before it worked — so you can skip the frustration:

  • ❌ Assuming JSON fields match table columns
    → Always inspect your actual data structure first.

  • ❌ Trying to render an array directly ({reading.book.authors})
    → Use .join(", ") for readable author lists.

  • ❌ Forgetting to capitalize status labels
    → "finished" → "Finished" with:

    js

  • ✅ Using reading.id as the key in .map()
    → Stable, unique, and required by React.

  • ✅ Keeping components small (<StatusFilter><BookTable>)
    → Makes testing and reuse easier.


What’s Next? (No Pressure, Just Options)

Now that the core works, here’s where I might go next — when I’m ready:

  1. Add interactivity: A “Mark as Finished” button that updates status in state.

  2. Mock a backend: Move readings.json behind a /api/books route using Vite’s proxy or a tiny Express server.

  3. Improve accessibility: Add ARIA labels to the filter dropdown.

  4. Style responsibly: Use CSS Modules (already started with BookTable.css) to avoid global conflicts.

None of these are urgent. The app already does what it needs to do.


Final Thought: Your Setup Doesn’t Have to Be “By the Book”

Tutorials teach idealized workflows. Real learning is messy, non-linear, and full of detours.

I kept my old files. I guessed at folder structures. I didn’t understand “derived state” until after I’d implemented it.

And that’s okay.

What matters isn’t whether you followed the “right” path — it’s that you built something that works, learned from it, and can now share that journey with others who feel just as unsure.

If you’re building your first React app over an existing project — you’re not doing it wrong. You’re doing it realistically.

And that’s worth writing about.


Like this post?
It’s part of my ongoing series on learning full-stack development in public.

Next up: “Why I Stopped Using Elementor — And Started Writing My Own HTML”

Author

  • Naoman Saeed

    I’m a self-taught developer building my way from code experiments to full-stack web solutions. At trogdyne.com, I share what I learn — from Flask and Docker to the realities of running a one-person digital agency in Pakistan.

Leave a Reply

Your email address will not be published. Required fields are marked *

Naoman

Saeed

I am a full stack web developer and technical writer passionate about MERN stack, self hosting & System thinking. This blog is my public notebook.