Today’s React progress was all about something fundamental but extremely important:
turning my FormSplitBill into a fully controlled form.
This sounds simple…
But once you start working with multiple inputs, derived values, and validation, you realize:
Controlled forms are not just about managing input.
They shape your app’s entire data-flow.
So here’s what I learned, how I refactored the form, and why it's a big milestone in my React journey.
🧩 What I Started With: (Partially Controlled Form)
Earlier, my form was somewhere between controlled and uncontrolled.
Some fields depended on React state, while others depended directly on the DOM.
For example, the "Friend’s Expense" field was calculated, but I wasn’t consistently handling input changes.
It worked…
but it wasn’t reliable.
🔥 Step 1 — Create State for Every Input
A controlled form means every input gets its value from state, and every change goes into state.
Here’s the core setup:
const [bill, setBill] = useState("");
const [yourExp, setYourExp] = useState("");
const paidByFriend = bill ? bill - yourExp : "";
const [whoIsPaying, setWhoIsPaying] = useState("user");
This immediately gives you:
- Single source of truth
- Predictable UI
- Easy debugging
🔥 Step 2 — Make Every Input Controlled
Before, my inputs were behaving independently.
Now each one has:
- A
valuecontrolled by state - An
onChangethat updates state
Example:
Bill input → full controlled version:
<input
type="text"
value={bill}
onChange={(e) => setBill(Number(e.target.value))}
/>
User expense input:
<input
type="text"
value={yourExp}
onChange={(e) =>
setYourExp(
Number(e.target.value) > bill ? yourExp : Number(e.target.value)
)
}
/>
Notice the second one contains validation logic — something uncontrolled forms make painful.
🌟 Step 3 — Derived Values Become Easy
Because everything is in React state, calculating values becomes clean:
const paidByFriend = bill ? bill - yourExp : "";
No querying DOM.
No refs.
No document.getElementById() nonsense.
Just pure React logic.
🔥 Step 4 — Make the Select Box Controlled Too
This was my favorite part.
Before:
- The dropdown worked
- But it didn’t store who was paying consistently
Now it’s clean:
<select
value={whoIsPaying}
onChange={(e) => setWhoIsPaying(e.target.value)}
>
<option value="user">You</option>
<option value="friend">{selectedFriend.name}</option>
</select>
One controlled select = predictable business logic.
🧠 What I Learned Today (Big Mindset Shift)
Converting the form to a fully controlled component forced me to understand:
✔ React state should always drive UI
✔ Inputs shouldn’t store their own values
✔ Derived values become cleaner when state is centralized
✔ Validation becomes easier
✔ Debugging becomes 10× simpler
Most importantly, I learned this:
A form isn’t just UI — it’s business logic.
And React controlled components give you full control over it.
🛠️ Next Step (Tomorrow’s Work)
➡ Connect form output to friend balance updates
➡ Add app-level state lifting
➡ Clean up small bugs in Add Friend form
➡ Improve UX with disable/enable logic
Top comments (0)