How to update fees in your React shopping cart based on check boxes.

I saw this question on Reddit recently:

“I’m currently writing an app that will apply a $25 fee amongst others that are depending on if the checkbox is checked or not. It’ll add the fee if it’s checked, but if the check is removed afterwards it’ll still keep the fee added on, how can I get the value removed if not checked after being checked? Here’s the code I’ve written for it.”

Ugh! Sounds horrible. A bug where something sort of half-works. How do you fix it? Which bit is half wrong? I’ve been in this situation many times myself.

Luckily, there is a way to have React state that behaves well, and as you would expect in your React app. You just need to shift how you think about React state just a little.

I could give a direct answer to the Reddit question to “just get it working”. However a tiny bit of rework can not only fix the bug, but make your life so much simpler now and forever in the future as you work on the same code.

When dealing with state problems in React, it is always worth thinking about this:

What you decide to NOT store in your state is perhaps the most important decision in your React components.

Please keep that in mind, and let’s dig into the Reddit problem:

The code posted is this:

const handleCheckBoxFour = (checked) => {
    if (!checked) {
      setLaptop(0);
    } else if (checked) {
      setLaptop(25);
    }
  };

<span className="leftspace">Laptop</span>
<input type="checkbox" onChange={handleCheckBoxFour}></input>

The first thing that popped out at me about this code is that you have a checkbox handler go update the numeric value of a fee.

Logically this seems a pretty fair enough thing to do. The requirements are probably “When they check this box, update the fee”, so that gets translated into code. Seems sensible! But there is a subtle problem.

If this was a plain JS app without React, this might be fine. However React cares deeply about it’s state, and as a result if you have one thing go change another thing in React state, you could make life harder for yourself.

The idea to think about in React is that there is a state, a source of truth, and a way to get from that state to a view you can show the user.

The code above is storing the $25 fee fact, but that’s one step away from the truth! The truth is simply “has the user checked the checkbox?”

If instead we store “has the user checked the checkbox”, we can use a common pattern in React called a controlled component. This one is a real trope and it’s super common: like a paint brush for a painter.

With a controlled component the value of your component always updates a piece of state directly and vice versa. There is no translation of “this is checked, let me see … it must be $25”. Instead we have a checkbox – let’s just record in our state that it’s checked:

<input type="checkbox" checked={isDeliveryChecked } onChange={() => {setIsDeliveryChecked (!isDeliveryChecked )}} ></input>

Then once you have the information about whether the value is checked, you can write a line like this:

const fee = (isDeliveryChecked ? 25 : 0)

And then use the fee variable somewhere in your JSX.

The reason this is simpler is because you are using a standard pattern – the controlled component which a React developer will have done 1000 times before. It’s like tying your shoelaces. And in combination you are using a single line of plain Javascript to deduce the fee.

That sort of code is easier to maintain and read, and most importantly, won’t have the bug.

Posted by Martin Capodici

.

Leave a Comment

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