UPDATE 2: See the "Read Solution" below
UPDATE: See the "Partial Solution" below
Yesterday was the inaugural meeting of the new ReactJS Developers meetup in Plano, Tx. It was a great chance to meet other local React developers and walk through a simple problem of "Thinking in React".
The goal was to recreate Dan Abramov's Overreacted blog in a simple React way but in a very short time frame.
I threw together a quick sample using Code Sandbox:
There's just one problem with it. Notice the information about the published date and reading time is commented out. If you uncomment it, 💥.
For some reason, details
is undefined. However, if you comment it back out and look at the amazing new React Dev Tools built directly into Code Sandbox, you'll see the BlogEntry
component is actually receiving the details
object in props:
This really ought to be a stupid simple fix. However, I've spent an hour on it and want to do this right now:
Anyone have some suggestions for how to solve this? If so, please feel free to fork it and send me a link on Twitter.
Partial Solution
My friend Fernando Ramirez pointed out a solution to the problem. He wraps the details section in some guards to make sure details
is defined.
P.S. Adding deeply nested guarding is really simple with Lodash#get or even using the new (but not TypeScript compatible - yet) Optional Conditional Chaining.
{details && details.date && (
<div>
Date: {details.date} Read Time: {details.readTime}
</div>
)}
While it is actually quite a good practice to add the guards in production in case your data is missing a property, I don't know why they are needed in general practice. In the current code base, why would details
ever be undefined
?
I've modified the original problem to log out when BlogEntry
gets rendered. Amazingly, the first time it is called with title
, details
, and blurb
all as undefined
. Why?
const BlogEntry = ({ title, details, blurb }) => {
console.log("Blog Entry Rendering", title, details, blurb);
return (
<li>
<h2>{title}</h2>
{/* Why does this work ??? */}
<div>{JSON.stringify(details)}</div>
{/* But this doesn't ????? 💥 */}
{/* <div>
{details.date} {details.readTime}
</div> */}
<p>{blurb}</p>
</li>
);
};
BlogEntry
is called 4 times and the first time results in:
Blog Entry Rendering undefined undefined undefined
Why is it called with no properties the first time?
Here's the modified version. If open the built-in console, you'll see the logging (in reverse order).
Real Solution
Well, I feel pretty stupid. Here was the real problem. Thanks for pointing it out @dta316.
In my code, I had an extra <BlogEntry />
with no attributes.
{/* 🤦♂️ OMG: THIS WAS THE PROBLEM. IT'S BEING CALLED HERE WITH NO PROPERTIES!! THANKS https://twitter.com/dta316
*/}
<BlogEntry />
You are calling it with no properties, see <BlogEntry /> on line 95, remove that and it works fine
— dta (@dta316) August 25, 2019