DEV Community

Cover image for πŸš€ Day 6 of Learning React: The Day React's Rendering Finally Started Making Sense (HMR, Bundlers & Form Handling)
Bismay.exe
Bismay.exe

Posted on

πŸš€ Day 6 of Learning React: The Day React's Rendering Finally Started Making Sense (HMR, Bundlers & Form Handling)

πŸ“Œ Missed Day 5? I explored React's Automatic Batching, why calling setState(count + 1) three times only increments once, and how functional updates with prev solve that problem. You can **read it here* and then come back. I'll wait. β˜•οΈ*


Yesterday's lesson answered one question:

Why doesn't React update immediately after every setState() call?

Today's class answered another one:

How does React know what to render?

At first, today's topics felt completely unrelated.

Rendering with map()...

Deleting product cards...

Hot Module Replacement...

Primitive and reference types...

Mutable and immutable values...

Form handling...

It honestly felt like React was throwing random concepts at me.

But somewhere in the middle of the class, something clicked.

Every single topic was connected by one idea:

React doesn't care that your data changed. It cares whether it can detect that something changed.

Once I started looking at today's lesson from that perspective, everything began making sense.

Let's dive in. πŸš€


🧠 Quick Recap

Yesterday's big question was:

Why doesn't setState() update immediately?

Here's what I took away from Day 5:

  • ⚑ React automatically batches multiple state updates.
  • πŸ“¦ State updates are stored in an internal update queue.
  • πŸ”„ Functional updates with prev always receive the latest available state.
  • πŸš€ Multiple setState() calls don't always mean multiple renders.

Today we're answering a different question:

How does React know what needs to be rendered? πŸ€”


πŸ›οΈ One Component... Twenty Product Cards

Today's project was much more interesting than rendering static JSX.

Instead of writing the same product card over and over again, I created a reusable ProductsCard component.

Then I stored 20 product objects inside state.

Rendering them was surprisingly simple.

{
  productsData.map((elem) => {
    return (
      <ProductsCard
        key={elem.id}
        product={elem}
        del={deleteProduct}
      />
    );
  });
}
Enter fullscreen mode Exit fullscreen mode

That single map() generated every product card on the screen.

If I had written twenty separate components manually...

I'd just be repeating the same code.

This reminded me of a programming principle we learned later in class:

DRY β€” Don't Repeat Yourself.

Instead of repeating UI, React encourages us to build reusable components and let data drive the interface.

That felt much cleaner.


πŸ—‘οΈ Simple Delete Function

Each product card had a Delete button.

Clicking it removed only that specific product.

The interesting part wasn't the button.

It was how React updated the screen.

const deleteProduct = (id) => {
  const products = productsData.filter(
    (elem) => elem.id !== id
  );

  setProductsData(products);
};
Enter fullscreen mode Exit fullscreen mode

Notice something?

I never removed any HTML.

I never searched for a DOM element.

I never called remove().

All I did was create a new array without the deleted product.

Then I updated the state.

React compared the new array with the previous one...

Re-rendered the component...

And only the missing card disappeared from the UI.

That was another reminder that in React, we don't usually manipulate the DOM ourselves.

We change the state.

React takes care of the UI.


πŸ”₯ Saving a File Isn't Magic β€” It's HMR

One thing I had never really paid attention to was what happens after pressing Ctrl + S.

The browser updates almost instantly.

But what's actually happening?

That's where Hot Module Replacement (HMR) comes in.

The moment I save a file, Vite immediately detects that something has changed. I even noticed it printing messages like this in the terminal:

Vite HMR terminal output

Every time I save a file, Vite logs an HMR update in the terminal, showing which modules were updated.

Seeing this made HMR feel much less "magical." Vite is constantly watching the project, and whenever a file changes, it knows exactly which module needs to be updated.

The process looks something like this:

Save File
      ↓
Vite Detects the Change
      ↓
Updates the Changed Module
      ↓
Browser Receives the Updated Code
      ↓
UI Updates Instantly ⚑
Enter fullscreen mode Exit fullscreen mode

Instead of refreshing the entire application, Vite only replaces the module that changed.

That's why development feels incredibly fast.


πŸ“¦ Bundlers Are Doing More Than I Thought

HMR also led us to bundlers.

Whenever our code changes, a bundler helps rebuild the project so the browser can understand it.

The flow looks like this:

React Files
      ↓
esbuild Transforms the Code
      ↓
Browser Executes JavaScript
Enter fullscreen mode Exit fullscreen mode

We talked about two bundlers in particular:

  • ⚑ esbuild β€” used during development because it's extremely fast.
  • πŸ“¦ Rollup β€” used for production builds because it focuses on creating optimized bundles.

I had heard both names before.

Today I finally understood where they fit into the development process.

During development, Vite mainly relies on esbuild because it's extremely fast.

When creating a production build, Vite uses Rollup to generate optimized bundles.


🎣 Looking at useState() From a Different Perspective

We've spent the last couple of days working with useState(), but today we summarized what it actually does.

const [count, setCount] = useState(0);
Enter fullscreen mode Exit fullscreen mode

This tiny Hook is responsible for several important things:

  • 🧠 Maintaining state.
  • ✏️ Updating state.
  • πŸ”„ Re-rendering its component.
  • ⚑ Making the UI interactive.

It may look simple...

But it's doing a lot behind the scenes.


🀯 The Object Experiment That Completely Confused Me

Numbers behaved exactly how I expected.

const [count, setCount] = useState(0);
Enter fullscreen mode Exit fullscreen mode

Then I tried storing an object.

const [user, setUser] = useState({
  name: "New User",
});
Enter fullscreen mode Exit fullscreen mode

I expected updating the object to work exactly like updating a number.

It didn't.

That confused me.

The solution turned out to be surprisingly simple.

Instead of changing the existing object...

I created a new object.

Suddenly everything worked.

That tiny change introduced me to one of the most important ideas in React.


🧩 Primitive vs Reference Types

To understand why the object behaved differently, we first talked about JavaScript values.

Primitive values include things like:

Number
String
Boolean
Enter fullscreen mode Exit fullscreen mode

Reference values include:

Object
Array
Function
Enter fullscreen mode Exit fullscreen mode

The biggest difference is that primitive values store the actual value.

Reference types store a reference to where that value lives in memory.

That difference becomes really important when React decides whether something has changed.


πŸ”„ Mutable vs Immutable β€” The Example That Made It Click

This was probably my favorite explanation from today's class.

Imagine you have a notebook.

πŸ“ Mutable

You erase what's written on page one.

Then you write something new on that same page.

The notebook is still the same notebook.

Only its contents changed.

Objects and arrays behave like this.

user.name = "Alex";
Enter fullscreen mode Exit fullscreen mode

The object is still the same object.

Only one property changed.


πŸ“„ Immutable

Now imagine making a photocopy of that notebook first.

You leave the original untouched.

Then you edit the copied version.

That's what immutable updates look like.

const updatedUser = {
  ...user,
  name: "Alex",
};
Enter fullscreen mode Exit fullscreen mode

Instead of changing the original object...

We create a brand new one.

React can easily detect that the reference has changed when you create a new object.

If you mutate the existing object, the reference stays the same, making it harder for React to know something changed.

That finally explained why creating a new object fixed my state update.


πŸ“ One Form, Three Different Approaches

The last topic I explored today was form handling.

More specifically...

Input handling.

What I found interesting wasn't the form itself.

It was how the solution became cleaner with every new approach.

The goal never changed.

Collect the user's input.

Only the implementation did.


1️⃣ Brute Force

The first approach was the most straightforward.

Every input had its own state.

const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
Enter fullscreen mode Exit fullscreen mode

Each input also had its own onChange.

<input onChange={(e) => setName(e.target.value)} />
<input onChange={(e) => setEmail(e.target.value)} />
<input onChange={(e) => setPassword(e.target.value)} />
Enter fullscreen mode Exit fullscreen mode

There's nothing wrong with this approach.

But after looking at it for a minute, the repetition becomes obvious.

Every new input means another state...

Another onChange...

And another piece of nearly identical code.


2️⃣ Better Approach

The next version reduced that repetition by storing everything inside a single object.

const [formData, setFormData] = useState({
  name: "",
  email: "",
  password: "",
});
Enter fullscreen mode Exit fullscreen mode

Updating an input looked like this:

<input
  onChange={(e) =>
    setFormData({
      ...formData,
      email: e.target.value,
    })
  }
/>
Enter fullscreen mode Exit fullscreen mode

One state object was enough to store every field.

Definitely cleaner.

But every input still repeated almost the same onChange logic.

Only the property name changed.


3️⃣ Optimized Approach

The final version was easily my favorite.

Instead of creating separate handlers...

One function handled every input.

const handleChange = (e) => {
  const { name, value } = e.target;

  setFormData({
    ...formData,
    [name]: value,
  });
};
Enter fullscreen mode Exit fullscreen mode

Now every input looked almost identical.

<input name="name" onChange={handleChange} />
<input name="email" onChange={handleChange} />
<input name="password" onChange={handleChange} />
Enter fullscreen mode Exit fullscreen mode

The clever part was this line:

[name]: value
Enter fullscreen mode Exit fullscreen mode

If the input's name is "email"...

React updates:

formData.email
Enter fullscreen mode Exit fullscreen mode

If the input's name is "password"...

React updates:

formData.password
Enter fullscreen mode Exit fullscreen mode

The same function works for every field.

No extra handlers.

No repeated logic.

Just one reusable solution.

That immediately reminded me of another principle from today's class:

DRY β€” Don't Repeat Yourself.

The optimized version wasn't just shorter.

It was much easier to maintain, especially as the number of inputs grows.


πŸ’‘ DRY β€” Don't Repeat Yourself

Today's optimized form perfectly demonstrated one principle:

DRY β€” Don't Repeat Yourself.

I noticed React encourages this idea everywhere.

Instead of writing twenty product cards...

We use map().

Instead of writing three different change handlers...

We use one reusable function.

Instead of building separate components that look almost identical...

We reuse the same component with different props.

The more I work with React, the more I realize it's constantly pushing me toward writing cleaner, reusable code.


πŸ’‘ My Mental Model

Here's how I connect today's topics in my head:

State Update
      ↓
React Compares the Previous State
      ↓
If Something Changed
      ↓
Component Re-renders
      ↓
Updated UI ✨
Enter fullscreen mode Exit fullscreen mode

Whether it's deleting a product...

Updating an object...

Or typing inside a form...

The same rendering process keeps happening behind the scenes.


πŸ’‘ My Biggest Takeaways Today

  • πŸ›οΈ map() lets us render large amounts of UI without repeating code.
  • πŸ—‘οΈ Updating state is enough for React to update the UIβ€”we rarely touch the DOM directly.
  • πŸ”₯ HMR instantly updates changed modules, making development much faster.
  • πŸ“¦ esbuild powers development, while Rollup creates optimized production builds.
  • 🧩 Objects and arrays are reference types, while numbers, strings, and booleans are primitive values.
  • πŸ”„ React prefers immutable updates because creating new objects and arrays makes changes easier to detect.
  • πŸ“ Form handling becomes much cleaner when one reusable function manages every input.
  • 🚫 DRY (Don't Repeat Yourself) is a principle that shows up everywhere in React.

πŸ“š Learning Source

I'm currently learning React through the React Cohort 3.0 by Devendra Dhote at Sheriyans Coding School.

This article isn't a copy of the course.

It's my personal understanding after today's class, rewritten entirely in my own words.

Writing these articles helps me reinforce what I've learned, and hopefully helps other beginners who are on the same journey. 🀝

If I've misunderstood something, I'd genuinely appreciate your corrections in the comments. 😊


πŸ™Œ Final Thoughts

Today's class looked overwhelming at first because it covered so many different topics.

But after connecting all the dots, I realized they all revolve around the same idea.

React needs a reliable way to know when something has changed.

Whether it's rendering a list with map(), deleting an item by updating state, creating a new object instead of mutating an old one, or building reusable form handlers, everything ultimately comes back to helping React render efficiently.

The more I learn React, the more I realize that most concepts eventually come back to one question:

How can React reliably detect that something has changed?

Today's class made that question much easier to answer.

See you on Day 7! πŸš€


πŸ’¬ Which concept took you the longest to understand when learning Reactβ€”rendering, immutability, or form handling? I'd love to hear what finally made it click for you. 😊

I'd love to hear your experience in the comments. 😊

If you're following along with this series, you can also find me on GitHub, where I'll be sharing my projects and documenting my progress.

Bismay-exe (Bismay.exe) Β· GitHub

πŸ‘‹ Hi, I’m Bismay πŸ’» Developer passionate about building clean, minimal, and elegant apps πŸš€ Focused on coding 🌱 Always learning, creating & new ideas - Bismay-exe

favicon github.com

πŸ€– AI Disclosure: This article is based on my own React learning journey, class notes, code experiments, and understanding. I used ChatGPT to help improve the writing, structure, and readability of this post. I reviewed and verified the technical explanations before publishing, and I take responsibility for everything shared here.

Thanks for reading! πŸš€


Top comments (1)

Collapse
 
sloan profile image
Sloan the DEV Moderator

Hey, this article appears to have been generated with the assistance of ChatGPT or possibly some other AI tool.

We allow our community members to use AI assistance when writing articles as long as they abide by our guidelines. Please review the guidelines and edit your post to add a disclaimer.

Failure to follow these guidelines could result in DEV admin lowering the score of your post, making it less visible to the rest of the community. Or, if upon review we find this post to be particularly harmful, we may decide to unpublish it completely.

We hope you understand and take care to follow our guidelines going forward!