-
I worked on two projects with Chris for Go Free Range, the first of which involved working with a React form to record numbers given by the user. We already had some
<select>
elements to do this, e.g.const Form = () => { const [unit, setUnit] = useState(1); const handleUnitChange = ({ target: { value }}) => { setUnit(parseFloat(value)); }; return ( <select value={unit} onChange={handleUnitChange}> <option value="1">m</option> <option value="100">cm</option> <option value="1000">mm</option> </select> ); };
This works fine. React is able to interpret our numeric value for
unit
and select the appropriate<option>
in our dropdown. When the user changes their selection, the corresponding value is passed tohandleUnitChange
and stored as a floating point number. This way, we keep ourunit
as a number throughout so it is ready to be passed to other functions without any coercion.However, if we try to do the same thing with an
<input type="text">
, we quickly run into trouble:const Form = () => { const [unit, setUnit] = useState(1); const handleUnitChange = ({ target: { value }}) => { setUnit(parseFloat(value)); }; return ( <input type="text" value={unit} onChange={handleUnitChange} /> ); };
What happens when the user tries to empty the field (e.g. perhaps to enter a new value from scratch)?
handleUnitChange
will fire with a value of an empty string:> parseFloat("") NaN
Perhaps then we try to avoid storing
NaN
and instead setunit
to beundefined
ornull
if it is falsy?const handleUnitChange = ({ target: { value }}) => { setUnit(value ? parseFloat(value) : undefined); // or setUnit(value ? parseFloat(value) : null); }
If we do this, when the user clears the field, React will log a warning that we’re switching a component from being controlled to being uncontrolled because setting the
value
of a field toundefined
ornull
has a special meaning: it tells React this field is now uncontrolled.Given it is totally valid for the user to enter an empty value, we realised we needed to separate our concerns: use strings for the
input
value but convert the value to a number when we pass it elsewhere in our application.const Form = () => { const [unit, setUnit] = useState("1"); const handleUnitChange = ({ target: { value }}) => { setUnit(value); }; doSomeCalculation(parseFloat(unit)); return ( <input type="text" value={unit} onChange={handleUnitChange} /> ); }; const doSomeCalculation = (unit) => { if (Number.isNaN(unit)) { return; } // ... };
Using an
<input type="number">
helps a little with this as it prevents non-numeric inputs firing theonChange
event but it seemed cleaner to deal with the problem in our logic than rely on browser behaviour. -
The second project Chris and I worked on involved a Python API written with Flask. Getting things running locally was quite a pain with my attempts to use pip to install NumPy ending in compilation errors. In the end, switching to the previous stable Python release of 3.8 (rather than the latest of 3.9) using pyenv solved my problems.
However, I was left with a bit of a mess of installed Homebrew formulae and wanted to clean things up. Thankfully, I found an answer on the macOS Super User with a great tip for removing unused Homebrew dependencies:
$ brew bundle dump $ brew bundle --force cleanup
This will first dump all explicitly installed formulae and casks into a
Brewfile
(which you could then edit) and then uninstall anything no longer required. -
I ended up in a similar mess after installing Xcode and
brew doctor
reported that I had out-of-date Command Line Tools.Attempting to use
xcode-select --install
failed with a strange error about the software update not being found and Software Update itself couldn’t install the update properly.It turns out that Xcode includes the Command Lines Tools itself even though I had a previous installation in
/Library/Developers/CommandLineTools
installed viaxcode-select
. I ended up completely removing both Xcode and the Command Line Tools and reinstalling the latter before Software Update could successfully pick up the right update. -
Simon wrote a truly excellent blog post about Rails autoloading with Zeitwerk titled “Rails autoloading — now it works, and how!”. This is a follow-up to his 2013 post “Rails autoloading — how it works, and when it doesn’t” to which I often found myself referring.
-
Following last week’s need for earplugs, I lost some hearing in my left ear. I returned from a trip to the pharmacy with some urea hydrogen peroxide and watched the Great British Bake Off sideways with the deeply unsettling sensation of fizzing in my ear canal.
I woke in the small hours of Thursday morning to find the room uncontrollably spinning around me. I staggered to the bathroom where I discovered I could no longer get my eyes to focus straight ahead without them constantly drifting to my right. With E’s help, I managed to speak to a doctor on the phone and go in to our local GP’s surgery to see someone in person that morning.
After waiting outside, the doctor greeted me at the door wrapped in plastic, said that they needed to “fire [their] gun” (a thermometer) at me and instructed me not to touch anything as we walked to a consultation room.
Thankfully, it’s a viral ear infection that’ll clear up by itself in a matter of days.
-
Now that C is confident enough walking, he happily roams our flat looking for things to prod, pull or combine in some way. We’ve already lost three bowls to his curiosity and I’ve had to rewire one plug. It also means that I took the step of lowering the mattress in his cot now that he more closely resembles the IKEA cartoon for “toddler” than the one for “baby”.
Weeknotes 54
By Paul Mucur,
on