CodeNewbie Community

Cover image for #3 | React with Hooks-Context: The Abstraction Wars (Mar 17, 2021)
Robert Lin
Robert Lin

Posted on

#3 | React with Hooks-Context: The Abstraction Wars (Mar 17, 2021)

Hello! Welcome! πŸ™‹β€β™‚οΈ

Quick Note for Newcomers πŸ‘‹

This is Week #3 in my "52 Weeks of Open-Source Adventures". Starting on March 6, 2021, I decided to start randomly roaming the internet and contributing one pull request to a different open-source project each week from all around the world. (I wrote a bit on why here.) So far, my travels have taken me to distant and exotic locales like The Philippines! And Singapore! And I've learned a ton at each stop (NextJS! Python linting!) but the true joy has been --of course-- all the newfound friends I've made along the way πŸ˜„. Anyway, if you're curious, tag along! I usually publish new posts each Tuesday; and with today's post, we're three weeks done with 49 left to go! Enjoy! πŸ€—


March 17, 2021

Location Oakland, California - USA
Maintainer @neurodynamic (Mark Stewart)
Repo kickstartcoding/reactjs.org (React with Hooks)
Mark's Website Kickstart Coding
Stack React, Gatsby

Contents:


Introduction:

Another Tuesday, another pull request! πŸ˜€ This week we fly from Singapore back home to the good ol' land of the Red, White, and Blue.

Talking about the good ol' Red, White, and Blue:

When I think of JavaScript, I think of America-- the land of the free and unrestrained. Like in America, in Javascriptlandia you can do just about anything to your heart's content. In JS, just like in the US, there are plenty of recommendations like "you really should wear a mask" but many people still choose not to. Or like you really shouldn't eat 75 hotdogs in 12 minutes but you totally still can. For better or for worse, rules are fast and loose and individuals are encouraged/resigned to always going their own way. This is America! And like in America, in JS, there's half-a-dozen ways to loop through a collection. You can code declaratively or imperatively. Out of the box, it's just a blank canvas-- awaiting your decree! When you're in Javascriptlandia, you're the king of the world-- you make all of the rules. And while you may soar to great, never hitherto heights of marvel and wonder-- you could also totally crash and burn too. It's all on you.

Because with extreme freedom also comes a sort of existential angst. And as it turns out, not all humans --especially newbies in the beginning-- are well-suited for radical, extreme freedom. Some of us (especially newbies) don't have any opinions. We simply just don't know enough yet to actually have opinions. We just want to be told what to do. We want guardrails! We want our hands held! We simply want a result to render on screen and, at least in the beginning, we don't care how that feat is accomplished.

I mean, think about it: When you were a toddler, did your parents just give you the keys to the car? Of course not; catastrophe and chaos would've surely ensued.

To combat all of this radical freedom and its accompanying existential angst, on the seventh day, God gave the world NPM. Packages for every single function and use case under the sun (obligatory link to the "Tale-of-Left-Pad" here). And with this newfound assist from God, Man was at last free.

But there was still a problem: Which package to choose from? All these options!

Anyway, long story short: Because I'd always considered myself a rebel (ha!), for nearly a decade now, I'd simply refused to learn/use React.1 You could say that I was "philosophically uninclined." As an old, I prided myself as someone who hailed from an era when "men were men." We didn't npm install xyz, we wrote it ourselves! We rolled up our sleeves and did the work. By God, this Dan Abramov kid from Russia is showing up and telling me to start with "create-react-app"? Like hell!

Well.

If I had a Dolorean, I'd travel back in the time and tell my younger self to simply wave the white flag and declare unconditional surrender. In the end, Sophie Bits and Dan Abramov won. It was a gallant resistance but we "manly men" totally lost. We were crushed and defeated, slaughtered like Gerald Butler's 300 at the Pass of Thermopylae…. Abstraction upon abstraction have won the day. And the abstractions are sufficiently complicated that they are actually entire worlds unto themselves now.

Because the simple truth of the matter --a truth that I'd been too naΓ―ve/immature/stubborn to see when I was a younger man-- is that at the day's end:


For a civilization to move forward and make progress, we need to at some point all get together and decide on our core values.


That is, the fundamental beliefs/values/prioritizations that we all share as a single society. If you take a beat, you'll quickly observe this calculus playing out everywhere around us in our daily lives, in the everyday world around us: In these times of COVID, how do we balance community health vs individual freedoms? Or in my hometown, for instance (Bozeman, MT; ftw! ✊), we even made national headlines recently: Do we value growth or affordable housing?

image
(Source: https://www.npr.org/2021/03/15/977533022/please-sell-me-a-home)

And in the software world: That yes, we may care about extensibility, but we care about 'ease-of-use' more. (Example: That newbies don't accidentally launch themselves into the sun when they git push on a branch with no upstream set.) Ultimately, like anything, the software world with all of its fancy frameworks and libraries nowadays are just various collections of opinions about tradeoffs.

In civilized society, we all decide to surrender some freedoms like to stop at red lights. But in return, as a whole, we collectively gain greater efficiencies by reducing traffic fatalities and hospitalizations. [Attribution: The Excellent Postlight Podcast-- I can't remember which episode! Will backfill later.] Yes, we surrender autonomy and submit our obedience; but in return, it allows us to build to even greater heights because we're now no longer litigating and relitigating settled issues on eternally-open/unanswerable questions. Is unidirectional dataflow really the answer? For now, yes. Deliberation is over; it's time for action.

As a final comment: In my mind's eye-- I will always think of Sophie Bits and Dan Abramov as a combo-wartime president like Lincoln or FDR. (I know the Core React team is huge; but these two, to me personally at least, are the public face of React. Though it'd be remiss to omit Jordan Walke, the guy who actually created the framework.) The point being: All these really smart people arrived on the scene and surveyed the lawless chaos that was the state of JS back in 2013/2014. And so they built their village out in the desert. And then we all flocked to it in droves. The two other notable alternatives, btw, (to my knowledge) are Vue.js

image

and Angular; and those frameworks have their own philosophies, fans, and followings. But the ideology is always the same: Surrender some free will and in return be granted peace, prosperity, and efficiency. πŸ˜„

…


[1] Though to be fair, in my own defense, when I first looked at React nearly a decade ago now, functional components with hooks didn't exist yet. Instead, all I remember seeing back in those days was what look like an incredibly cumbersome framework of class-based components with half-a-dozen lifecycle methods. It honestly looked a lot like ASPX/.NET!


This Week's Pull Request: React with Hooks

Background & Motivation:

React with Hooks (16.8.0) first released on February 6, 2019-- about 26 months ago. But following its release, documentation was still sparse. In that mien, Mark Stewart of Kickstart Coding --based out of Oakland, CA!-- set out to convert the entirety of the original documentation to be hook-based. To be clear, this was an unofficial conversion, but it proved to be so popular and helpful that it even got pinned and directly linked to in the official ReactJS Issues tracker (by the very talented Rachel Nabors!)

image

image

Since I was learning React brand new in 2021, and wanted to of course learn the "latest and greatest" (obviously; who wants to learn old stuff?!), it was via Rachel's post that I found my way to Mark's unofficial docs, which he'd published on Sep 1, 2020.

So I dutifully followed Mark's write-up and everything went well. Having some experience with ASPX and .NET, I was already pretty familiar with component-based paradigms for GUI work so I picked up everything relatively quickly (different decade, same/similar ideas, it often feels like πŸ€”) but when I reached the Context section in Mark's docs, his example struck me as awfully clunky so I opened up an issue in his repo:

image

to which he promptly replied to later that afternoon:

image

Basically, I was perplexed by the need to set multiple contexts just to pass around context handlers. Surely, there was a better way? Anyway, Mark couldn't think of a better way either so the challenge was on! πŸ˜€


Coding Time:

Next to sliced bread and the Guttenberg printing press, online code editors like CodeSandbox and CodePen are one of humanity's great inventions. Without having to bring down any code locally, I'd found a CodeSandbox that a user by the name of armenic had originally created and linked to in the issue thread. So by building off his code (open-source/global collaboration ftw! ✊) and reading the docs for React class components, I was able to figure out how to combine both context providers into a single provider:

image

Great! So now the next step was simply integrating these changes into Mark's actual documentation. However this is where I encountered my first roadblock! πŸ™πŸ˜¦β˜Ή


Roadblock:

image
(Source: https://gijoe.fandom.com/wiki/Roadblock(Movie)_)

So usually, nowadays in 2021 at least, you fork and clone a git repo and it just works, right?

Wrong!

To my dismay, once I pulled down Mark's code and tried to run yarn dev on it, I got this nasty stack trace:

image

Very uncool. So now what? Do we just throw our hands up and give up?

No way! It's 2021! Looking at react/reactjs.org repo, I see there are 863 other contributors to the project:

image

Thus, clearly-- if 863 other random humans across the planet could build and run the reactjs.org docs site locally, then so could the Open-Source Avenger!! πŸ˜πŸ˜„πŸ˜€ Our next step, therefore, is everyone's standard move:

image

Jackpot! And clicking in:

image

And digging through that thread, I eventually found:
image

which led me to:

image

Ah, here lies the answer to our mystery! As a long-suffering Windows developer, seeing Windows-specific errors like this no longer surprises me πŸ™„. I remember years ago when I first started learning Ruby on Rails and following Michael Hartl's book, there was a similar "datetime TZ" bug too. The details elude me now, so many years later, but the general gist is that for decades, people who develop on Windows machines are often treated as "second-class citizens." Folks, especially in the open-source world, had historically just coded and confirmed that their code worked on Unix or MacOS (which is built on Unix) and then Windows developers were just left out in the cold. β›„πŸ˜“β„πŸ₯ΆπŸŒ¨β˜ƒπŸ§Š

With Nadella at the helm of Microsoft now since 2014, it's been improving (with stuff like Windows Terminal, WSL, buying GitHub) but if you're a developer who works on Windows, buckle up for a wild ride. Occasionally, code that seemingly works for everyone else will not work for you!

So, a few observations to notice here: vladar's PR was merged into the trunk of reactjs/reactjs.org back in Aug 2020. But Mark's fork of reactjs.org was:

image

Meaning that while vladar's PR was merged with reactjs:master, Mark hadn't yet brought it down. When you start working in open-source, it'll be common that sometimes you're working on a fork of someone else's fork! (This is the entire spirit of open-source!) So when this does happen, and you encounter unexpected errors or behaviors, it's useful to go back to the trunk and search through issues there in the original repo. This was a good experience I learned working on this week's PR! πŸ˜€

Anyway, long story short, I updated the issue tracker with my findings and included links to let know Mark know what PRs he could pull from reactjs:master in case he wanted to fix this problem:

image

And on my own machine, looking at vladar's PR, I simply made this change locally to appease the GraphQL Gods so the reactjs docs site would build and run locally on my Windows machine:

image

To be clear: I did not include these changes in my own PR. I wanted my PR to be solely contained to updating the Context section of Mark's documentation. When you submit PRs, it's a good practice to only submit one PR per thing.


An Interesting Discovery: JAMstack

Building and running Mark's fork of the ReactJS docs site was the first time I encountered GraphQL and Gatsby. I was entirely new to this stack and immediately out-of-the-box, my first impression was unfavorable! 😀

Here's what happened:

Documentation sites, generally speaking, are pretty straightforward. We're basically just talking about serving static content to the end user. No interactivity or anything fancy. I'm not going to dive into the whole shebang here, but back in 2015, JAMstack became a thing. I've only lightly investigated, but from what I'm able to gather, the gist is that static sites are making a comeback, specifically in the form of JavaScript, APIs, and Markup.

The Markup keyword, especially, is key. Back when I went into hibernation in the spring of 2014, markdown, if I remember using it at all, was solely the province of README.md, I think. And maybe some WYSIWYG editors used it? Like TinyMCE? Those prehistoric days were honestly so long ago, it feels like another lifetime πŸ€”. But at least, I don't seem to remember entire static sites being built out of Markdown.

But now it's 2021 and entire static sites are built in Markdown. If you think about it, it actually makes a ton of sense. Markdown's decently expressive and paired with an npm module like Remarkable, you can easily convert markdown into HTML that's ready to serve.

So, from what I'm able to gather: Gatsby --at least the little I've dealt with it-- has essentially done this:

  • You initialize a new project with some starter boilerplate.
  • In a "content" folder, start organizing your docs, all in markdown: image
  • At then at the top of every markdown, you then identify the document with a standard header, like this: image

The reactjs docs site is exactly this. It's essentially just a collection of a ton of markdown pages.


So Where Does GraphQL Enter the Picture?

That content folder is essentially just a "static database", if you think about it. It's all static content and what Gatsby's essentially done (I think) is just super-compressed all of that static content and sent it to all CDNs everywhere around the globe. Then, additionally, they've built clever logic so that anytime you mouse-over a link, under the hood, the webpage you're reading will make an AJAX call to preload that content from the CDN nearest to your physical location, deliver the compressed/minified payload to your browser (or mobile device), and unpack it. By doing this "pre-caching" or "lookahead-fetching", Gatsby (and these JAMstack sites) are able to achieve super-fast "loading." Because by the time you click on the link, the browser's already done some of the work! The page you want to read next has already been partially fetched!

Under the hood, to make all of the "fast magic" happen, Gatsby leverages GraphQL. As far as I can discern, GraphQL is just the API for how the GatsbyJS framework accesses that "static database" material.

This part is important: When you run the Gatsby dev server and are developing locally, the very first time you render a page (say, the ReactJS Context page), Gatsby will do all of the heavy-lifting to read, parse, and then cache the contents of the context.md. That way, if you navigate back to context.md, it'll just be instantly delivered since it's already been accessed once and was thus cached.

Btw, context.md looks like this:

image

And then sprinkled throughout context.md were these bits:

embed:context/motivation-problem.js

These embed snippets tell Gatsby to go and look at these other files:

image

and fetch those embedded example snippets:

image
to then beautifully paint on the actual webpage:

image


Okay, So the Problem?

So, to Gatsby's credit, if I make changes to the markdown of context.md, the Gatsby dev server is smart enough to detect the change and recompile the page with my markdown changes. The moment you change the markdown, like:

image

the Gatsby dev server dutifully detects that:

image

and the webpage auto-hot-reloads accordingly:

image

Okay, so that's nice. This is good 2021 "dev ergonomics." Good job, Gatsby. So I navigate to the example .js snippets that Mark had written in his converted docs and change them accordingly. But to my surprise, Gatsby doesn't detect those changes. That's right, anything changed in the embedded code snippets don't reflect in the webpage.

image

To get these changes to show up, I had to either clean and restart the entire Gatsby server OR also change something bogus in the parent context.md file in order to "trick" Gatsby into hot-reloading my changes. (There's actually also another caching issue I encountered too, related to this, but I won't bore you with here. Suffice it to say, the first time I saw this, it really left me scratching my head.)

Anyway, like the dutiful sleuth I am, I obviously Googled to see if I was doing something wrong. Maybe there was a flag I was missing somewhere? A setting I could flip to bypass the "clever caching"?

(After all, caching isn't exactly a bad thing. For example, as a brief aside: Earlier this morning, I was playing around with writing some tests in Go and my test results (which were testing something that depended on random generation internally) were being cached. Luckily, like usual, SO saved me and you just pass in -count=1 to bypass Go's internal caching.):

image

But nope. After more time Googling than actually coding Mark's PR, I eventually found this:

image

Ah, so they know about this issue! But it's closed? But… was it ever fixed?

I scroll to the bottom of the thread:

image

and then:

image

They just closed! Without fixing it! Argh!!!! πŸ˜€πŸ€¦β€β™‚οΈπŸ˜€πŸ€¦β€β™‚οΈ

Of course, I could've just left it here. But that just didn't sit right with me. It's a known issue! How can it just be closed, unresolved?!?!? Some OCD part of my brain combusted. πŸ’₯πŸ’£πŸ§¨πŸ€― In times like this, when I feel like some grave injustice has been committed against the Universe, I go and read Bill Gate's famous "Windows Usability Systematic degradation flame" which comforts me. I keep a copy on my desktop that I can click on, at any time. Salve for the soul.

Anyway, keeping in mind that Gatsby is 100% free, partially open-source, and shared out of generosity and love, I instead just choose to leave a polite message:

image

Oh, and I also just ended up in-lining all of my code snippet examples in context.md and did this:

image

Bye! πŸ‘‹πŸ‘‹πŸ‘‹


Wrapping Up

Finally, I went ahead and made the code changes and submitted my PR:

image

As usual, I included some helpful notes in my PR, included the deploy preview link that Netlify generated after I submitted. Around this time when I was writing everything up, I also found Mark's own blog post that he'd written, describing his experience converting the docs. And it amused me that he also tripped over the very same "Autorefresh Limitations" that too had frustrated me:

image

To Mark's credit, he's got ten-thousand times the patience that I personally lack and was able to find the wherewithal to do a full cycle of Gatsby (omg) every time he wanted to see changes. πŸ‘πŸ‘πŸ‘


Then a few days ago, Mark merged my PR! πŸ˜€πŸ˜πŸ˜Š

image

image

PR #3 in the bag! πŸ€—


Epilogue:

I really enjoyed working on this PR! Learning React with Hooks was neat and I got the hang of it pretty quickly. And I am proud of having contributing documentation to all of humanity! πŸ˜€

This was also my first time writing documentation and code examples like this and that was a ton of fun. As I go through this "52-Weeks-of-Open-Source" journey, I think I'm increasingly learning that my absolute dream job would be write documentation and code small toy examples for a living. I don't know if a job like that actually exists but I find it enormously satisfying and fulfilling. And every week you're learning something 100% new! And helping others learn too! And then the next week, it's onto some bright, new, shiny thing! 😁

Also: I think the really cool part was seeing Gatsby for the first time. Oh man, static-site generation has come a long way! It is really impressive and I'm honestly torn. On one hand, it feels enormously overengineered. But on the other hand, reading through their rationale about code-splitting and leveraging CDNs to "pre-deliver" stuff to make it the fastest UX possible also makes sense. Also, just the sheer spectacle of something like GatsbyJS does impress me. It's kinda like when Elon Musk sent that Tesla Roadster into space. πŸŽπŸš€ On some level, the fact humanity has achieved this sort of abstraction and tooling for static-site generation does make me proud to be member of the species! πŸ€“

Alrighty, and that's all for this week. Same time, same channel next week! Hopefully see you then! Until then, Open-Source Avenger out! πŸ˜„βœ¨πŸš’


PS. Btw: Congratulations on reading this far and finishing this whole thing! 3,626 words! For your efforts, the prize this week, a lovely song 😊:

Discussion (0)