Skip to content

Instantly share code, notes, and snippets.

@jgierer12
Created July 22, 2019 01:50
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jgierer12/e4e92eefddd14f1ace4f671f4507365d to your computer and use it in GitHub Desktop.
Save jgierer12/e4e92eefddd14f1ace4f671f4507365d to your computer and use it in GitHub Desktop.
This file has been truncated, but you can view the full file.
<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title><![CDATA[Kent C. Dodds]]></title>
<description><![CDATA[Come check out how Kent C. Dodds can help you level up your career as a software engineer.]]></description>
<link>https://kentcdodds.com</link>
<generator>RSS for Node</generator>
<lastBuildDate>Fri, 19 Jul 2019 20:25:23 GMT</lastBuildDate>
<item>
<title><![CDATA[When to break up a component into multiple components]]></title>
<description><![CDATA[Current Available Translations: Korean Did you know that you could write any React Application as a single React
Component? There's absolutely nothing technically stopping React from putting
your entire application into one giant component. Your…]]></description>
<link>https://kentcdodds.com/blog/when-to-break-up-a-component-into-multiple-components</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/when-to-break-up-a-component-into-multiple-components</guid>
<pubDate>Fri, 19 Jul 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;Current Available Translations:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://edykim.com/ko/post/when-to-break-up-a-component-into-multiple-components"&gt;Korean&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Did you know that you could write any React Application as a single React
Component? There&amp;#x27;s absolutely nothing technically stopping React from putting
your entire application into one giant component. Your function would be HUGE.
There&amp;#x27;d be a TON of hooks for state and side-effects, but it&amp;#x27;s totally possible.&lt;/p&gt;&lt;p&gt;If you tried this though you&amp;#x27;d face a few problems:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Performance would probably suffer: Every state change results in a re-render
of the entire application.&lt;/li&gt;&lt;li&gt;Code sharing/reusability would be... not easy. At least if you made it a
class component, which you might have to do if you wanted to use
&lt;code&gt;componentDidCatch&lt;/code&gt; to handle runtime errors. If you were allowed to use
&lt;code&gt;react-error-boundary&lt;/code&gt; so you could use hooks, then it would be
&lt;em&gt;considerably&lt;/em&gt; easier. But... I digress...&lt;/li&gt;&lt;li&gt;State would be a challenge: Knowing which pieces of state and event handlers
went with what parts of JSX would make your head hurt 😬 and lead to some
hard to track down bugs 🐜 (This is one benefit of the separation of
concerns).&lt;/li&gt;&lt;li&gt;Testing would be 100% integration:
&lt;a href="https://kentcdodds.com/blog/write-tests"&gt;Not necessarily an altogether bad thing&lt;/a&gt;, but it would
be pretty tough to test edge cases and keep things isolated to the parts
that you&amp;#x27;re trying to test, so you would suffer big-time from over-testing
(which is &lt;a href="https://kentcdodds.com/blog/common-testing-mistakes"&gt;a common mistake in E2E testing&lt;/a&gt;).&lt;/li&gt;&lt;li&gt;Working together on the codebase with multiple engineers would just be
terrible. Can you imagine the git diffs and merge conflicts?!&lt;/li&gt;&lt;li&gt;Using third party component libraries would be... ummm... impossible? If
we&amp;#x27;re writing everything as a single component third party libraries is at
odds with that goal! And even if we allowed using third party components,
what about HOCs like &lt;a href="https://emotion.sh"&gt;react-emotion&lt;/a&gt;? Not allowed!
(Besides, you should &lt;a href="https://emotion.sh/docs/css-prop"&gt;use the &lt;code&gt;css&lt;/code&gt; prop&lt;/a&gt;
anyway 😉).&lt;/li&gt;&lt;li&gt;Encapsulating imperative abstractions/APIs in a more declarative component
API wouldn&amp;#x27;t be allowed either meaning that the imperative API would be
littered throughout the lifecycle hooks of our one giant component, leading
to harder to follow code. (Again, unless you&amp;#x27;re using hooks, in which case
you could group relevant hooks together, making it easier to manage, but
still a bit of a nightmare).&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;These are the reasons that we write custom components. It allows us to solve
these problems.&lt;/p&gt;&lt;p&gt;I&amp;#x27;ve had a question on my AMA for a while:
&lt;a href="https://github.com/kentcdodds/ama/issues/399"&gt;Best ways/patterns to split app into components&lt;/a&gt;.
And this is my answer: &amp;quot;When you experience one of the problems above, that&amp;#x27;s
when you break your component into multiple smaller components. NOT BEFORE.&amp;quot;
Breaking a single component into multiple components is what&amp;#x27;s called
&amp;quot;abstraction.&amp;quot; Abstraction is awesome, but
&lt;a href="https://kentcdodds.com/blog/aha-programming"&gt;every abstraction comes with a cost&lt;/a&gt;, and you have to be
aware of that cost and the benefits before you take the plunge&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;&lt;a href="https://www.sandimetz.com/blog/2016/1/20/the-wrong-abstraction"&gt;&amp;quot;Duplication is far cheaper than the wrong abstraction.&amp;quot;&lt;/a&gt;
— &lt;a href="https://twitter.com/sandimetz"&gt;Sandi Metz&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;So I don&amp;#x27;t mind if the JSX I return in my component function gets really long.
Remember that JSX is just a bunch of JavaScript expressions using the
declarative APIs given by components. Not a whole lot can go wrong with code
like that and it&amp;#x27;s much easier to keep that code as it is than breaking out
things into a bunch of smaller components and start
&lt;a href="https://kentcdodds.com/blog/prop-drilling"&gt;Prop Drilling&lt;/a&gt; everywhere.&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;So feel free to break up your components into smaller ones, but don&amp;#x27;t be afraid
of a growing component until you start experiencing real problems. It&amp;#x27;s WAY
easier to maintain it until it needs to be broken up than maintain a pre-mature
abstraction. Good luck!&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/when-to-break-up-a-component-into-multiple-components"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Write tests. Not too many. Mostly integration.]]></title>
<description><![CDATA[Current Available Translations: Korean Russian Portuguese I've given this blog post as a talk which you can watch here: https://youtu.be/Fha2bVoC8SE?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf A while back, Guillermo Rauch‏ (creator of
Socket.io and…]]></description>
<link>https://kentcdodds.com/blog/write-tests</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/write-tests</guid>
<pubDate>Sat, 13 Jul 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;Current Available Translations:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://www.vobour.com/%ED%85%8C%EC%8A%A4%ED%8A%B8%EB%A5%BC-%EC%9E%91%EC%84%B1%ED%95%98%EC%9E%90-%EB%84%88%EB%AC%B4-%EB%A7%8E%EC%9D%B4%EB%8A%94-%EB%A7%90%EA%B3%A0-%ED%86%B5%ED%95%A9-%EC%9C%84%EC%A3%BC%EB%A1%9C-write-tests"&gt;Korean&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://howtorecover.me/napisite-testy-ne-sliskom-mnogo"&gt;Russian&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://medium.com/@sergioamjr91/escreva-testes-n%C3%A3o-muitos-mas-mais-de-integra%C3%A7%C3%A3o-7ebebf225516"&gt;Portuguese&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I&amp;#x27;ve given this blog post as a talk which you can watch here:&lt;/p&gt;&lt;p&gt;&lt;iframe width="100%" height="315" src="https://www.youtube-nocookie.com/embed/Fha2bVoC8SE?rel=0&amp;amp;list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf" frameBorder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""&gt;&lt;/iframe&gt;&lt;/p&gt;&lt;p&gt;A while back, &lt;a href="https://twitter.com/rauchg"&gt;Guillermo Rauch‏&lt;/a&gt; (creator of
&lt;a href="https://socket.io"&gt;Socket.io&lt;/a&gt; and founder of &lt;a href="https://zeit.co"&gt;Zeit.co&lt;/a&gt; (the
company behind a ton of the awesome stuff coming out lately))
&lt;a href="https://twitter.com/rauchg/status/807626710350839808"&gt;tweeted something profound&lt;/a&gt;:&lt;/p&gt;&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;Write tests. Not too many. Mostly integration.&lt;/p&gt;— Guillermo ▲ (@rauchg) &lt;a href="https://twitter.com/rauchg/status/807626710350839808"&gt;December 10, 2016&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Write tests. Not too many. Mostly integration.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;This is deep, albeit short, so let&amp;#x27;s dive in:&lt;/p&gt;&lt;h2&gt;Write tests.&lt;/h2&gt;&lt;p&gt;Yes, for most projects you should write automated tests. You should if you value
your time anyway. Much better to catch a bug locally from the tests than getting
a call at 2:00 in the morning and fix it then. &lt;strong&gt;Often I find myself saving time
when I put time in to write tests.&lt;/strong&gt; It may or may not take longer to implement
what I&amp;#x27;m building, but I (and others) will almost definitely save time
maintaining it.&lt;/p&gt;&lt;p&gt;The thing you should be thinking about when writing tests is how much confidence
they bring you that your project is free of bugs. Static typing and linting
tools like &lt;a href="https://www.typescriptlang.org"&gt;TypeScript&lt;/a&gt; and
&lt;a href="https://eslint.org"&gt;ESLint&lt;/a&gt; can get you a remarkable amount of confidence, and
if you&amp;#x27;re not using these tools I highly suggest you give them a look. That
said, &lt;strong&gt;even a strongly typed language should have tests.&lt;/strong&gt; Typing and linting
can&amp;#x27;t ensure your business logic is free of bugs. So you can still seriously
increase your confidence with a good test suite.&lt;/p&gt;&lt;h2&gt;Not too many.&lt;/h2&gt;&lt;p&gt;I&amp;#x27;ve heard managers and teams mandating 100% code coverage for applications.
That&amp;#x27;s a really bad idea. The problem is that &lt;strong&gt;you get diminishing returns on
your tests as the coverage increases much beyond 70%&lt;/strong&gt; (I made that number up...
no science there). Why is that? Well, when you strive for 100% all the time, you
find yourself spending time testing things that really don&amp;#x27;t need to be tested.
Things that really have no logic in them at all (so any bugs could be caught by
ESLint and Flow). &lt;em&gt;Maintaining tests like this actually really slow you and your
team down.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;You may also find yourself testing implementation details just so you can make
sure you get that one line of code that&amp;#x27;s hard to reproduce in a test
environment. You &lt;em&gt;really&lt;/em&gt; want to avoid testing implementation details because
it doesn&amp;#x27;t give you very much confidence that your application is working and it
slows you down when refactoring. &lt;strong&gt;You should very rarely have to change tests
when you refactor code.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;I should mention that almost all of my open source projects have 100% code
coverage. This is because most of my open source projects are smaller libraries
and tools that are reusable in many different situations (a breakage could lead
to a serious problem in a lot of consuming projects) and they&amp;#x27;re relatively easy
to get 100% code coverage on anyway.&lt;/p&gt;&lt;h2&gt;Mostly integration.&lt;/h2&gt;&lt;p&gt;There are all sorts of different types of testing (check out my 5 minute talk
about it at Fluent Conf:
&lt;a href="https://youtu.be/Da9wfQ0frGA?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;&amp;quot;What we can learn about testing from the wheel&amp;quot;&lt;/a&gt;).
They each have trade-offs. The three most common forms of testing we&amp;#x27;re talking
about when we talk of automated testing are: Unit, Integration, and End to End.&lt;/p&gt;&lt;p&gt;Here&amp;#x27;s &lt;a href="http://slides.com/kentcdodds/testing-workshop#/4/8"&gt;a slide&lt;/a&gt; from my
Frontend Masters workshop:
&lt;a href="https://frontendmasters.com/courses/testing-javascript"&gt;&amp;quot;Testing JavaScript Applications&amp;quot;&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:800px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/20c422f5dad15169acfae9613c561dad/8ff1e/2.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:62.5%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="testing pyramid" title="testing pyramid" src="https://kentcdodds.com/static/20c422f5dad15169acfae9613c561dad/8ff1e/2.png" srcSet="https://kentcdodds.com/static/20c422f5dad15169acfae9613c561dad/f4a45/2.png 259w,https://kentcdodds.com/static/20c422f5dad15169acfae9613c561dad/ef0f6/2.png 518w,https://kentcdodds.com/static/20c422f5dad15169acfae9613c561dad/8ff1e/2.png 800w" sizes="(max-width: 800px) 100vw, 800px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;This testing pyramid is a combination of one I got from
&lt;a href="https://martinfowler.com/bliki/TestPyramid.html"&gt;Martin Fowler&amp;#x27;s blog&lt;/a&gt; and one
I got from
&lt;a href="https://testing.googleblog.com/2015/04/just-say-no-to-more-end-to-end-tests.html"&gt;the Google Testing blog&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;As indicated here, the pyramid shows from bottom to top: Unit, Integration, E2E.
As you move up the pyramid the tests get slower to write/run and more expensive
(in terms of time and resources) to run/maintain. It&amp;#x27;s meant to indicate that
you should spend more of your time on unit tests due to these factors.&lt;/p&gt;&lt;p&gt;One thing that it doesn&amp;#x27;t show though is that &lt;strong&gt;as you move up the pyramid, the
confidence quotient of each form of testing increases.&lt;/strong&gt; You get more bang for
your buck. So while E2E tests may be slower and more expensive than unit tests,
they bring you much more confidence that your application is working as
intended.&lt;/p&gt;&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;The TestPyramid blog post by &lt;a href="https://twitter.com/martinfowler"&gt;@martinfowler&lt;/a&gt; (&lt;a href="https://t.co/RCv8abFm37"&gt;https://t.co/RCv8abFm37&lt;/a&gt;) finishes with this note.&lt;br/&gt;&lt;br/&gt;Our tools are awesome now and this assumption is less true. This is why I say goodby to the pyramid 🔼 and hello to the trophy 🏆 &lt;a href="https://t.co/EKTK4vqj6n"&gt;https://t.co/EKTK4vqj6n&lt;/a&gt; &lt;a href="https://t.co/Wa8brUiWfy"&gt;pic.twitter.com/Wa8brUiWfy&lt;/a&gt;&lt;/p&gt;— Kent C. Dodds (@kentcdodds) &lt;a href="https://twitter.com/kentcdodds/status/1141365123296051201"&gt;June 19, 2019&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;&lt;p&gt;As noted, our tools have moved beyond the assumption in Martin&amp;#x27;s original
Testing Pyramid concept. This is why I created &amp;quot;The Testing Trophy&amp;quot; 🏆&lt;/p&gt;&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;&amp;quot;The Testing Trophy&amp;quot; 🏆&lt;br/&gt;&lt;br/&gt;A general guide for the **return on investment** 🤑 of the different forms of testing with regards to testing JavaScript applications.&lt;br/&gt;&lt;br/&gt;- End to end w/ &lt;a href="https://twitter.com/Cypress_io"&gt;@Cypress_io&lt;/a&gt; ⚫️&lt;br/&gt;- Integration &amp;amp; Unit w/ &lt;a href="https://twitter.com/fbjest"&gt;@fbjest&lt;/a&gt; 🃏&lt;br/&gt;- Static w/ &lt;a href="https://twitter.com/flowtype"&gt;@flowtype&lt;/a&gt; 𝙁 and &lt;a href="https://twitter.com/geteslint"&gt;@geteslint&lt;/a&gt; ⬣ &lt;a href="https://t.co/kPBC6yVxSA"&gt;pic.twitter.com/kPBC6yVxSA&lt;/a&gt;&lt;/p&gt;— Kent C. Dodds (@kentcdodds) &lt;a href="https://twitter.com/kentcdodds/status/960723172591992832"&gt;February 6, 2018&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;Here&amp;#x27;s a humorous other illustration of the importance of integration tests:&lt;/p&gt;&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;expect(umbrellaOpens).toBe(true)&lt;br/&gt;&lt;br/&gt;tests: 1 passed, 1 total&lt;br/&gt;&lt;br/&gt;**all tests passed** &lt;a href="https://t.co/p6IKO7KDuy"&gt;pic.twitter.com/p6IKO7KDuy&lt;/a&gt;&lt;/p&gt;— Erin 🦁 (@erinfranmc) &lt;a href="https://twitter.com/erinfranmc/status/1148986961207730176"&gt;July 10, 2019&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;&lt;p&gt;It doesn&amp;#x27;t matter if your component &lt;code&gt;&amp;lt;A /&amp;gt;&lt;/code&gt; renders component &lt;code&gt;&amp;lt;B /&amp;gt;&lt;/code&gt; with props
&lt;code&gt;c&lt;/code&gt; and &lt;code&gt;d&lt;/code&gt; if component &lt;code&gt;&amp;lt;B /&amp;gt;&lt;/code&gt; actually breaks if prop &lt;code&gt;e&lt;/code&gt; is not supplied. So
while having some unit tests to verify these pieces work in isolation isn&amp;#x27;t a
bad thing, &lt;em&gt;it doesn&amp;#x27;t do you any good if you don&amp;#x27;t &lt;strong&gt;also&lt;/strong&gt; verify that they
work together properly.&lt;/em&gt; And you&amp;#x27;ll find that by testing that they work together
properly, you often don&amp;#x27;t need to bother testing them in isolation.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Integration tests strike a great balance on the trade-offs between confidence
and speed/expense.&lt;/strong&gt; This is why it&amp;#x27;s advisable to spend &lt;em&gt;most&lt;/em&gt; (not all, mind
you) of your effort there.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;For more on this read
&lt;a href="https://kentcdodds.com/blog/testing-implementation-details"&gt;Testing Implementation Details&lt;/a&gt;. For
more about the different distinctions of tests, read
&lt;a href="https://kentcdodds.com/blog/unit-vs-integration-vs-e2e-tests"&gt;Static vs Unit vs Integration vs E2E Testing for Frontend Apps&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;h2&gt;How to write more integration tests&lt;/h2&gt;&lt;p&gt;The line between integration and unit tests is a little bit fuzzy. Regardless, I
think the biggest thing you can do to write more integration tests is to &lt;strong&gt;stop
mocking so much stuff&lt;/strong&gt;. &lt;em&gt;When you mock something you’re removing all confidence
in the integration between what you’re testing and what’s being mocked.&lt;/em&gt; I
understand that &lt;a href="https://kentcdodds.com/blog/the-merits-of-mocking"&gt;sometimes it can’t be helped&lt;/a&gt;
(though &lt;a href="https://youtu.be/EaxDl5NPuCA"&gt;some would disagree&lt;/a&gt;). You don’t
&lt;em&gt;actually&lt;/em&gt; want to send emails or charge credit cards every test, but most of
the time you can avoid mocking and you’ll be better for it.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;If you’re doing React, then this includes shallow rendering.&lt;/strong&gt; For more on
this, read
&lt;a href="https://kentcdodds.com/blog/why-i-never-use-shallow-rendering"&gt;Why I Never Use Shallow Rendering&lt;/a&gt;.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;I don&amp;#x27;t think that anyone can argue that testing software is a waste of time.
The biggest challenge is &lt;a href="https://kentcdodds.com/blog/how-to-know-what-to-test"&gt;knowing what to test&lt;/a&gt;
and how to test it in a way that gives
&lt;a href="https://kentcdodds.com/blog/confidently-shipping-code"&gt;true confidence&lt;/a&gt; rather than the false
confidence of
&lt;a href="https://kentcdodds.com/blog/testing-implementation-details"&gt;testing implementation details&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;I hope this is helpful to you and I wish you the best luck in your goals to find
confidence in shipping your applications!&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/write-tests"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[React Fundamentals: Props vs State]]></title>
<description><![CDATA[Let's compare props and state. Here's a definition of each: "props" (short for "properties") is an object of arbitrary inputs a React
function component accepts as the first argument. "state" is data that changes over the lifetime of a specific…]]></description>
<link>https://kentcdodds.com/blog/props-vs-state</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/props-vs-state</guid>
<pubDate>Mon, 08 Jul 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;Let&amp;#x27;s compare props and state. Here&amp;#x27;s a definition of each:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&amp;quot;props&amp;quot; (short for &amp;quot;properties&amp;quot;) is an object of arbitrary inputs a React
function component accepts as the first argument.&lt;/li&gt;&lt;li&gt;&amp;quot;state&amp;quot; is data that changes over the lifetime of a specific instance of a
React component.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Let&amp;#x27;s dive into each.&lt;/p&gt;&lt;h2&gt;Props&lt;/h2&gt;&lt;p&gt;Think of props as arguments to a function. React components are functions which
return JSX (or more generally something that&amp;#x27;s renderable like React elements,
&lt;code&gt;null&lt;/code&gt;, a string, etc.). Typically when you have a piece of code that you would
like to reuse, you can place that code into a function and any dynamic values
that code used before can be accepted as arguments (for example
&lt;code&gt;const five = 2 + 3&lt;/code&gt; could be extracted to a function and accept arguments like
so &lt;code&gt;const five = add(2, 3)&lt;/code&gt;).&lt;/p&gt;&lt;p&gt;The same is true of a piece of JSX, except instead of calling it like a normal
function (&lt;code&gt;add(2, 3)&lt;/code&gt;) you use JSX syntax (&lt;code&gt;&amp;lt;Add n1={2} n2={3} /&amp;gt;&lt;/code&gt;). The
&amp;quot;attributes&amp;quot; supplied in the JSX are what are called &lt;code&gt;props&lt;/code&gt; and they are placed
together in a single object and passed to the &lt;code&gt;Add&lt;/code&gt; component function as the
first argument like so:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx" metastring="{1}"&gt;function Add(props) {
return (
&amp;lt;div&amp;gt;
{props.n1} + {props.n2} = {props.n1 + props.n2}
&amp;lt;/div&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If I were to use this like so:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;&amp;lt;Add n1={2} n2={3} /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here&amp;#x27;s how that would be rendered:&lt;/p&gt;&lt;div style="padding:14px;background-color:rgba(0,0,0,0.05);border-radius:4px;margin-bottom:20px"&gt;&lt;div&gt;2 + 3 = 5&lt;/div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;p&gt;NOTE: Props can be anything. In our example they&amp;#x27;re numbers, but they can also
be (and often are) strings, arrays, objects, functions, etc.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Let&amp;#x27;s say we want to default the &lt;code&gt;n2&lt;/code&gt; to &lt;code&gt;0&lt;/code&gt; in the event someone doesn&amp;#x27;t
provide it (like &lt;code&gt;&amp;lt;Add n1={2} /&amp;gt;&lt;/code&gt;). &lt;strong&gt;One limit to props is that you&amp;#x27;re not
allowed to change them.&lt;/strong&gt; So you couldn&amp;#x27;t do something like this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;function Add(props) {
if (typeof props.n2 === &amp;#x27;undefined&amp;#x27;) {
props.n2 = 0
}
return (
&amp;lt;div&amp;gt;
{props.n1} + {props.n2} = {props.n1 + props.n2}
&amp;lt;/div&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If we try to do this, we&amp;#x27;ll get the following error:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;TypeError: Cannot add property n2, object is not extensible
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is simple enough to solve though:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;function Add(props) {
let n2 = props.n2
if (typeof n2 === &amp;#x27;undefined&amp;#x27;) {
n2 = 0
}
return (
&amp;lt;div&amp;gt;
{props.n1} + {n2} = {props.n1 + n2}
&amp;lt;/div&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Or, often, you&amp;#x27;ll find people use destructuring syntax with default values as
well (this is my personal preference):&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;function Add({n1, n2 = 0}) {
return (
&amp;lt;div&amp;gt;
{n1} + {n2} = {n1 + n2}
&amp;lt;/div&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is awesome, but what if I want to dynamically change the props value? Let&amp;#x27;s
say I wanted to build something like this:&lt;/p&gt;&lt;div style="padding:14px;background-color:rgba(0,0,0,0.05);border-radius:4px;margin-bottom:20px"&gt;&lt;div&gt;2 + &lt;input type="number" aria-label="n2" value="0"/&gt; = 2&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Without state, here&amp;#x27;s how I might try to accomplish that:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx" metastring="{5}"&gt;function AddWithInput(props) {
function handleInputChange(event) {
const input = event.target
const newN2 = Number(input.value)
props.n2 = newN2
}
return (
&amp;lt;div&amp;gt;
{props.n1} +{&amp;#x27; &amp;#x27;}
&amp;lt;input type=&amp;quot;number&amp;quot; value={props.n2} onChange={handleInputChange} /&amp;gt; ={&amp;#x27; &amp;#x27;}
{props.n1 + props.n2}
&amp;lt;/div&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;However, this will not work for two reasons:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;React doesn&amp;#x27;t know that we&amp;#x27;ve updated the &lt;code&gt;n2&lt;/code&gt; value of our &lt;code&gt;props&lt;/code&gt; object,
so it wont update the DOM when we change &lt;code&gt;props.n2&lt;/code&gt;, so we wont see our
changes anyway&lt;/li&gt;&lt;li&gt;We&amp;#x27;ll get the &lt;code&gt;TypeError&lt;/code&gt; warning as before&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;This is where state comes in.&lt;/p&gt;&lt;h2&gt;State&lt;/h2&gt;&lt;p&gt;State is data that changes over time, and that&amp;#x27;s perfect for our situation:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx" metastring="{2, 7}"&gt;function AddWithInput(props) {
const [n2, setN2] = React.useState(0)
function handleInputChange(event) {
const input = event.target
const newN2 = Number(input.value)
setN2(newN2)
}
return (
&amp;lt;div&amp;gt;
{props.n1} +{&amp;#x27; &amp;#x27;}
&amp;lt;input type=&amp;quot;number&amp;quot; value={n2} onChange={handleInputChange} /&amp;gt; ={&amp;#x27; &amp;#x27;}
{props.n1 + n2}
&amp;lt;/div&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That will work, and this is precisely what React state is intended to be used
for. It&amp;#x27;s intended to track data values over the lifetime of the component (so
long as the component exists on the page).&lt;/p&gt;&lt;p&gt;However, users of the &lt;code&gt;AddWithInput&lt;/code&gt; component can no longer set the initial
value of &lt;code&gt;n2&lt;/code&gt; anymore. With the way that component is implemented currently,
it&amp;#x27;s not referencing &lt;code&gt;props.n2&lt;/code&gt; at all. But we can make this work by using props
when we initialize our state:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;function AddWithInput(props) {
const [n2, setN2] = React.useState(props.n2)
// ... etc...
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now if someone were to do this: &lt;code&gt;&amp;lt;AddWithInput n1={2} n2={3} /&amp;gt;&lt;/code&gt; then the result
would look like this (notice that the initial input value is &lt;code&gt;3&lt;/code&gt;):&lt;/p&gt;&lt;div style="padding:14px;background-color:rgba(0,0,0,0.05);border-radius:4px;margin-bottom:20px"&gt;&lt;div&gt;2 + &lt;input type="number" aria-label="n2" value="3"/&gt; = 5&lt;/div&gt;&lt;/div&gt;&lt;p&gt;So our props are &amp;quot;arguments&amp;quot; or &amp;quot;inputs&amp;quot; that we can pass to a component, and
state is something that is managed within the component and can change over
time.&lt;/p&gt;&lt;p&gt;Let me just clean this component up a little bit and I&amp;#x27;ll explain my changes:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx" metastring="{1, 2}"&gt;function AddWithInput({n1, initialN2 = 0}) {
const [n2, setN2] = React.useState(initialN2)
function handleInputChange(event) {
const input = event.target
const newN2 = Number(input.value)
setN2(newN2)
}
return (
&amp;lt;div&amp;gt;
{n1} + {&amp;#x27; &amp;#x27;}
&amp;lt;input type=&amp;quot;number&amp;quot; value={n2} onChange={handleInputChange} /&amp;gt; ={&amp;#x27; &amp;#x27;}
{n1 + n2}
&amp;lt;/div&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I changed to destructuring with defaults for the props, and I changed the prop
from &lt;code&gt;n2&lt;/code&gt; to &lt;code&gt;initialN2&lt;/code&gt;. When I&amp;#x27;m using a prop value to initialize a state
value, I typically like to give it the prefix &lt;code&gt;initial&lt;/code&gt; to communicate that
changes in that prop will not be taken into account. If that&amp;#x27;s what you want,
then you&amp;#x27;ll want to
&lt;a href="https://reactjs.org/docs/lifting-state-up.html"&gt;Lift State Up&lt;/a&gt;.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;I hope this helps clear up the difference between props and state in React for
you. It&amp;#x27;s a foundational concept. Go ahead and test yourself on this little app
below. Where&amp;#x27;s the state, where are the props?&lt;/p&gt;&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/react-codesandbox-oov7o?view=editor" style="width:100%;height:500px;border-width:0px;border-radius:4px;overflow:hidden"&gt;&lt;/iframe&gt;&lt;/p&gt;&lt;p&gt;I hope that&amp;#x27;s helpful! Good luck!&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/props-vs-state"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[How I Teach]]></title>
<description><![CDATA[I've been teaching programming for a long time. From the very beginning
actually. I signed up to be a tutor in my first programming class. I did it out
of an effort to
solidify what I was learning . Through the
years, I've changed the way that I…]]></description>
<link>https://kentcdodds.com/blog/how-i-teach</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/how-i-teach</guid>
<pubDate>Mon, 01 Jul 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;I&amp;#x27;ve been teaching programming for a long time. From the very beginning
actually. I signed up to be a tutor in my first programming class. I did it out
of an effort to
&lt;a href="https://kentcdodds.com/blog/solidifying-what-you-learn"&gt;solidify what I was learning&lt;/a&gt;. Through the
years, I&amp;#x27;ve changed the way that I teach programming concepts to people.&lt;/p&gt;&lt;p&gt;In the last few years, I read a book that totally changed the way I think about
learning and teaching. When I was in school, I found myself constantly
&amp;quot;cramming&amp;quot; for tests. Spending hours before the test just re-reading the text
over and over again hoping it would stick. I couldn&amp;#x27;t tell you anything about
the stuff I crammed, because I can&amp;#x27;t remember it at all. I didn&amp;#x27;t retain that
information.&lt;/p&gt;&lt;p&gt;In my teaching, I&amp;#x27;m not interested in hooking people up to a firehose of
information and turning on the water. That&amp;#x27;s easy. We all have tons of
information in our individual brains that we could just talk about for hours.
Doing that doesn&amp;#x27;t do anyone any good. I&amp;#x27;m more interested in ensuring that the
things I teach find a place in the students&amp;#x27; brains and stay locked in forever.
So I&amp;#x27;ve studied and experimented and one method has been the most effective for
me for the last few years and I want to share the concept with you now.&lt;/p&gt;&lt;p&gt;I read a book a few years ago about this. It&amp;#x27;s called
&lt;a href="https://makeitstick.net"&gt;Make It Stick: The Science of Successful Learning&lt;/a&gt; and
it was a game changer for me. I recommend you pick it up and give it a
read/&lt;a href="https://www.audible.com/pd/Make-It-Stick-Audiobook/B00M0EO7EY"&gt;listen&lt;/a&gt;,
but here&amp;#x27;s a great summary video about it:&lt;/p&gt;&lt;p&gt;&lt;iframe width="100%" height="315" src="https://www.youtube-nocookie.com/embed/tQsIlnuAB9E?rel=0" frameBorder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""&gt;&lt;/iframe&gt;&lt;/p&gt;&lt;p&gt;In that book, I learned that everything I knew about studying and learning was
totally wrong. And because of this I couldn&amp;#x27;t teach as effectively. Learning how
people learn and master material made a big impact on the way that I approach
teaching it.&lt;/p&gt;&lt;p&gt;Here are a few of the things that I started doing after reading this book:&lt;/p&gt;&lt;h3&gt;Generation - Desirable Difficulties&lt;/h3&gt;&lt;blockquote&gt;&lt;p&gt;Make and challenge assumptions about brand new concepts&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I have people &lt;em&gt;do&lt;/em&gt; the exercises before I teach the concepts they&amp;#x27;ll be
learning. I use &amp;quot;emoji guides&amp;quot;
(&lt;a href="https://github.com/kentcdodds/react-fundamentals/blob/b230ea412aaaca50ecf2537c0cf72516cd0e68e1/src/exercises/06.js#L6-L18"&gt;like this&lt;/a&gt;)
so they can actually get something accomplished during the exercise. Sometimes
the emoji guides do a ton of hand holding. But making attendees go through the
exercise first opens their brain to prepare it for learning.&lt;/p&gt;&lt;p&gt;This is often pretty uncomfortable for people. Especially for traditional
learners, we&amp;#x27;re used to attending a lecture, listening to someone talk for an
hour, and writing down everything they&amp;#x27;re saying. That may help you become good
at transcribing what someone&amp;#x27;s saying very quickly, but it&amp;#x27;s not going to help
you learn the material.&lt;/p&gt;&lt;p&gt;By struggling and facing challenges first, your brain has to work and you have
to make and challenge assumptions that you have about what it is you&amp;#x27;re
learning. The beautiful thing about this is that once you&amp;#x27;ve made a decision
based on your assumption you&amp;#x27;re either correct or you&amp;#x27;re not.&lt;/p&gt;&lt;p&gt;If your assumption was correct, then you get a shot of dopamine which will lodge
the knowledge into your brain better. You&amp;#x27;re not going to get that same shot of
dopamine if someone just tells you the answer without you struggling to get
there.&lt;/p&gt;&lt;p&gt;If your assumption was incorrect, then you remember it even better because
there&amp;#x27;s a bit of a disappointed feeling associated with getting it wrong and
&lt;a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5573739"&gt;that strong emotion will solidify that experience into your memory&lt;/a&gt;.
(I should note that this is generally an internal dialog/experience that is
personal for each learner and their misconceptions are only made known to other
learners if they choose to share them during the instruction).&lt;/p&gt;&lt;p&gt;Having to struggle through the new concepts before being taught that material is
one of the ways I teach people and help them retain what they&amp;#x27;re learning.&lt;/p&gt;&lt;h3&gt;Interleave Practice&lt;/h3&gt;&lt;blockquote&gt;&lt;p&gt;Mix up what you&amp;#x27;re learning/practicing as you&amp;#x27;re learning new things&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;In the book (and as described in the summary video), they reference a study
where baseball players practiced using different approaches. One group practiced
hitting the same pitch over and over again, then moved on to a different pitch
and practiced that over and over again. The other group had the pitches mixed
up. The one which mixed up the kinds of pitches they received performed better.
We can do that in the things that we&amp;#x27;re learning and the way we teach as well.&lt;/p&gt;&lt;p&gt;This one is a bit harder to do in a single day workshop with specific things
that we want to learn, but in my material I try to get this by having the
exercises build upon one another so people see the new things they&amp;#x27;ve been
learning on as they work on learning something new.&lt;/p&gt;&lt;h3&gt;Elaboration&lt;/h3&gt;&lt;blockquote&gt;&lt;p&gt;Describe what you learned in your own words.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;At the end of &lt;em&gt;every&lt;/em&gt; exercise, I have a link to an &amp;quot;Elaboration and Feedback&amp;quot;
form specific to the exercise. This is where I invite people to write down a few
of the things that they learned (in their own words). Doing this helps them to
connect what they&amp;#x27;ve learned to things they already know which is another
important element for retention.&lt;/p&gt;&lt;p&gt;This one also benefits me because it&amp;#x27;s an opportunity for me to receive some
quick feedback on the material so I can find places to improve things. I&amp;#x27;ve been
doing this in my workshops since the beginning of 2017, and now over a year and
a half later I have 3.6k responses to this form. Not everyone fills out the
feedback and elaboration form, but I have been able to see which exercises and
working and which aren&amp;#x27;t based on the responses I get here.&lt;/p&gt;&lt;h3&gt;Active Retrieval&lt;/h3&gt;&lt;blockquote&gt;&lt;p&gt;Intentionally go back and make your brain try to remember what it&amp;#x27;s naturally
forgetting.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;All of my workshop material is available as an open source project on GitHub
(&amp;quot;available for private, non-commercial use under the GPL version 3&amp;quot;). I
encourage everyone who takes the workshop material to go through it all again a
week later to interrupt the natural forgetting process that our brains do
automatically (think of it as natural garbage collection).&lt;/p&gt;&lt;p&gt;What&amp;#x27;s best is if the workshop attendee can put what they&amp;#x27;ve learned into
practice. However, because I can&amp;#x27;t do much about deciding what they work on in
their day job, the next best thing I can do is make the material available for
them to go through again and encourage them to do so.&lt;/p&gt;&lt;p&gt;By practicing it again and actively retrieving the things your brain is in the
process of forgetting, you tell your brain &amp;quot;nope, this is important, keep it
around please.&amp;quot; The more you do that, the better you&amp;#x27;ll remember it, which is
one reason why I make the material freely available and encourage people to go
through it again a week after the workshop. (This is actually specific advice
that I received from one of the authors of &amp;quot;Make It Stick&amp;quot; when I reached out to
them via email).&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;Teaching and learning are not easy. It takes a lot of work. But if you take some
time to learn how to learn, it might just make you a more effective learner and
teacher. Unfortunately, due to the limited time that I have when I&amp;#x27;m teaching
(normally only a day or two), some of the principles can&amp;#x27;t be applied as well as
others, but adapting and applying the principles I learned from Make It Stick
has been the most effective way to teach and ensure the retention of what I
teach. I hope this was helpful to you. Good luck!&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/how-i-teach"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[One simple trick to optimize React re-renders]]></title>
<description><![CDATA[I was preparing a blog post on a subject related to React re-renders when I
stumbled upon this little React gem of knowledge I think you'll really
appreciate: https://twitter.com/kentcdodds/status/1143200604065431552 After reading this blog post…]]></description>
<link>https://kentcdodds.com/blog/optimize-react-re-renders</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/optimize-react-re-renders</guid>
<pubDate>Mon, 24 Jun 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;I was preparing a blog post on a subject related to React re-renders when I
stumbled upon this little React gem of knowledge I think you&amp;#x27;ll really
appreciate:&lt;/p&gt;&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;If you give React the same element you gave it on the last render, it wont bother re-rendering that element.&lt;/p&gt;— Kent C. Dodds (@kentcdodds) &lt;a href="https://twitter.com/kentcdodds/status/1143200604065431552"&gt;June 24, 2019&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;&lt;p&gt;After reading this blog post,
&lt;a href="https://twitter.com/BrooksLybrand"&gt;Brooks Lybrand&lt;/a&gt; implemented this trick and
this was the result:&lt;/p&gt;&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;A little before and after optimization on a react component.&lt;br/&gt;&lt;br/&gt;I didn&amp;#x27;t use any memoization to accomplish this, yet I was able to go from a 13.4ms to a 3.6ms render.&lt;br/&gt;&lt;br/&gt;I also didn&amp;#x27;t do anything besides move code into an extra component, which ended up cutting out 27 lines of code. &lt;a href="https://t.co/xrUN0MUm5Y"&gt;pic.twitter.com/xrUN0MUm5Y&lt;/a&gt;&lt;/p&gt;— Brooks Lybrand (@BrooksLybrand) &lt;a href="https://twitter.com/BrooksLybrand/status/1149800755404185609"&gt;July 12, 2019&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;&lt;p&gt;Excited? Let&amp;#x27;s break it down with a simple contrived example and then talk
about what practical application this has for you in your day-to-day apps.&lt;/p&gt;&lt;h2&gt;An example&lt;/h2&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;// play with this on codesandbox: https://codesandbox.io/s/react-codesandbox-g9mt5
import React from &amp;#x27;react&amp;#x27;
import ReactDOM from &amp;#x27;react-dom&amp;#x27;
function Logger(props) {
console.log(`${props.label} rendered`)
return null // what is returned here is irrelevant...
}
function Counter() {
const [count, setCount] = React.useState(0)
const increment = () =&amp;gt; setCount(c =&amp;gt; c + 1)
return (
&amp;lt;div&amp;gt;
&amp;lt;button onClick={increment}&amp;gt;The count is {count}&amp;lt;/button&amp;gt;
&amp;lt;Logger label=&amp;quot;counter&amp;quot; /&amp;gt;
&amp;lt;/div&amp;gt;
)
}
ReactDOM.render(&amp;lt;Counter /&amp;gt;, document.getElementById(&amp;#x27;root&amp;#x27;))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When that&amp;#x27;s run, &amp;quot;counter rendered&amp;quot; will be logged to the console initially, and
each time the count is incremented, &amp;quot;counter rendered&amp;quot; will be logged to the
console. This happens because when the button is clicked, state changes and
React needs to get the new React elements to render based on that state change.
When it gets those new elements, it renders and commits them to the DOM.&lt;/p&gt;&lt;p&gt;Here&amp;#x27;s where things get interesting. Consider the fact that
&lt;code&gt;&amp;lt;Logger label=&amp;quot;counter&amp;quot; /&amp;gt;&lt;/code&gt; never changes between renders. It&amp;#x27;s static, and
therefore could be extracted. Let&amp;#x27;s try that just for fun (I&amp;#x27;m not recommending
you do this, wait for later in the blog post for practical recommendations).&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;// play with this on codesandbox: https://codesandbox.io/s/react-codesandbox-o9e9f
import React from &amp;#x27;react&amp;#x27;
import ReactDOM from &amp;#x27;react-dom&amp;#x27;
function Logger(props) {
console.log(`${props.label} rendered`)
return null // what is returned here is irrelevant...
}
function Counter(props) {
const [count, setCount] = React.useState(0)
const increment = () =&amp;gt; setCount(c =&amp;gt; c + 1)
return (
&amp;lt;div&amp;gt;
&amp;lt;button onClick={increment}&amp;gt;The count is {count}&amp;lt;/button&amp;gt;
{props.logger}
&amp;lt;/div&amp;gt;
)
}
ReactDOM.render(
&amp;lt;Counter logger={&amp;lt;Logger label=&amp;quot;counter&amp;quot; /&amp;gt;} /&amp;gt;,
document.getElementById(&amp;#x27;root&amp;#x27;),
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Did you notice the change? Yeah! We get the initial log, but then we don&amp;#x27;t get
new logs when we click the button anymore! WHAAAAT!?&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;If you want to skip all the deep-dive technical details and get to the &amp;quot;what
does this mean for me&amp;quot; go ahead and &lt;a href="#practical"&gt;plop yourself down there now&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;h2&gt;What&amp;#x27;s going on?&lt;/h2&gt;&lt;p&gt;So what&amp;#x27;s causing this difference? Well, it has to do with React elements. Why
don&amp;#x27;t you take a quick break and read my blog post
&lt;a href="https://kentcdodds.com/blog/what-is-jsx"&gt;&amp;quot;What is JSX?&amp;quot;&lt;/a&gt; to get a quick refresher on React elements
and their relationship to JSX.&lt;/p&gt;&lt;p&gt;When React calls the counter function, it gets back something that looks a bit
like this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;// some things removed for clarity
const counterElement = {
type: &amp;#x27;div&amp;#x27;,
props: {
children: [
{
type: &amp;#x27;button&amp;#x27;,
props: {
onClick: increment, // this is the click handler function
children: &amp;#x27;The count is 0&amp;#x27;,
},
},
{
type: Logger, // this is our logger component function
props: {
label: &amp;#x27;counter&amp;#x27;,
},
},
],
},
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;These are called UI descriptor objects. They describe the UI that React should
create in the DOM (or via native components for react native). Let&amp;#x27;s click the
button and take a look at the changes:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript" metastring="{8,9}"&gt;const counterElement = {
type: &amp;#x27;div&amp;#x27;,
props: {
children: [
{
type: &amp;#x27;button&amp;#x27;,
props: {
onClick: increment,
children: &amp;#x27;The count is 1&amp;#x27;,
},
},
{
type: Logger,
props: {
label: &amp;#x27;counter&amp;#x27;,
},
},
],
},
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As far as we can tell, the only changes are the &lt;code&gt;onClick&lt;/code&gt; and &lt;code&gt;children&lt;/code&gt; props
of the &lt;code&gt;button&lt;/code&gt; element. However, the entire thing is completely new! Since the
dawn of time using React, you&amp;#x27;ve been creating these objects brand new on every
render. (Luckily, even mobile browsers are pretty fast at this, so that has
never been a significant performance problem).&lt;/p&gt;&lt;p&gt;It may actually be easier to investigate at the parts of this tree of React
elements is the same between renders, so here are the things that did NOT change
between those two renders:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript" metastring="{2,6,13,15}"&gt;const counterElement = {
type: &amp;#x27;div&amp;#x27;,
props: {
children: [
{
type: &amp;#x27;button&amp;#x27;,
props: {
onClick: increment,
children: &amp;#x27;The count is 1&amp;#x27;,
},
},
{
type: Logger,
props: {
label: &amp;#x27;counter&amp;#x27;,
},
},
],
},
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;All the element types are the same (this is typical), and the &lt;code&gt;label&lt;/code&gt; prop for
the Logger element is unchanged. However the props object itself changes every
render, even though the properties of that object are the same as the previous
props object.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Ok, here&amp;#x27;s the kicker right here.&lt;/strong&gt; Because the Logger props object has
changed, React needs to re-run the Logger function to make sure that it doesn&amp;#x27;t
get any new JSX based on the new props object (in addition to effects that may
need to be run based on the props change). &lt;strong&gt;But what if we could prevent the
props from changing between renders?&lt;/strong&gt; If the props don&amp;#x27;t change, then React
knows that our effects shouldn&amp;#x27;t need to be re-run and our JSX shouldn&amp;#x27;t change
(&lt;a href="https://en.wikipedia.org/wiki/Idempotence#Computer_science_meaning"&gt;because React relies on the fact that our render methods should be idempotent&lt;/a&gt;).
This is exactly what React is coded to do
&lt;a href="https://github.com/facebook/react/blob/d420d2ccb6223a66d5e8fe824ac0d31ed5bf87a1/packages/react-reconciler/src/ReactFiberBeginWork.js#L2571-L2575"&gt;right here&lt;/a&gt;
and it&amp;#x27;s been that way since React first started!&lt;/p&gt;&lt;p&gt;Ok, but the problem is that
&lt;a href="https://github.com/facebook/react/blob/745baf2e061bdb7a07b511fa6fd8c1c5e8106313/packages/react/src/ReactElement.js#L177"&gt;react creates a brand new &lt;code&gt;props&lt;/code&gt; object every time we create a React element&lt;/a&gt;,
so how do we ensure that the props object doesn&amp;#x27;t change between renders?
Hopefully now you&amp;#x27;ve got it and you understand why the second example above
wasn&amp;#x27;t re-rendering the Logger. If we create the JSX element once and re-use
that same one, then we&amp;#x27;ll get the same JSX every time!&lt;/p&gt;&lt;h2&gt;Let&amp;#x27;s bring it back together&lt;/h2&gt;&lt;p&gt;Here&amp;#x27;s the second example again (so you don&amp;#x27;t have to scroll back up):&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;// play with this on codesandbox: https://codesandbox.io/s/react-codesandbox-o9e9f
import React from &amp;#x27;react&amp;#x27;
import ReactDOM from &amp;#x27;react-dom&amp;#x27;
function Logger(props) {
console.log(`${props.label} rendered`)
return null // what is returned here is irrelevant...
}
function Counter(props) {
const [count, setCount] = React.useState(0)
const increment = () =&amp;gt; setCount(c =&amp;gt; c + 1)
return (
&amp;lt;div&amp;gt;
&amp;lt;button onClick={increment}&amp;gt;The count is {count}&amp;lt;/button&amp;gt;
{props.logger}
&amp;lt;/div&amp;gt;
)
}
ReactDOM.render(
&amp;lt;Counter logger={&amp;lt;Logger label=&amp;quot;counter&amp;quot; /&amp;gt;} /&amp;gt;,
document.getElementById(&amp;#x27;root&amp;#x27;),
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So let&amp;#x27;s checkout the &lt;em&gt;things that are the same&lt;/em&gt; between renders:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript" metastring="{2,6,12-17}"&gt;const counterElement = {
type: &amp;#x27;div&amp;#x27;,
props: {
children: [
{
type: &amp;#x27;button&amp;#x27;,
props: {
onClick: increment,
children: &amp;#x27;The count is 1&amp;#x27;,
},
},
{
type: Logger,
props: {
label: &amp;#x27;counter&amp;#x27;,
},
},
],
},
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Because the Logger element is completely unchanged (and therefore the props are
unchanged as well), React can automatically provide this optimization for us and
not bother re-rendering the Logger element because it shouldn&amp;#x27;t need to be
re-rendered anyway. This is basically like &lt;code&gt;React.memo&lt;/code&gt; except instead of
checking each of the props individually, React is checking the props object
holistically.&lt;/p&gt;&lt;div style="position:relative"&gt;&lt;a name="practical" style="position:absolute;top:-100px"&gt;&lt;/a&gt;&lt;/div&gt;&lt;h2&gt;So what does this mean for me?&lt;/h2&gt;&lt;p&gt;In summary, if you&amp;#x27;re experiencing performance issues, try this:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&amp;quot;Lift&amp;quot; the expensive component to a parent where it will be rendered less
often.&lt;/li&gt;&lt;li&gt;Then pass the expensive component down as a prop.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;You may find doing so solves your performance problem without needing to spread
&lt;code&gt;React.memo&lt;/code&gt; all over you codebase like a giant intrusive band-aid 🤕😉&lt;/p&gt;&lt;h2&gt;Demo&lt;/h2&gt;&lt;p&gt;Creating a practical demo of a slow app in React is tricky because it kinda
requires building a full app, but I do have a contrived example app that has a
before/after that you can check out and play with:&lt;/p&gt;&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/react-codesandbox-qtdob" style="width:100%;height:500px;border-width:0px;border-radius:4px;overflow:hidden"&gt;&lt;/iframe&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;One thing I want to add is that even though it&amp;#x27;s &lt;em&gt;better&lt;/em&gt; to use the faster
version of this code, it&amp;#x27;s still performing really badly when it renders
initially and it would perform really badly if it ever actually needed to do
another top-down re-render (or when you update the rows/columns). That&amp;#x27;s a
performance problem that should probably be dealt with on its own merits
(irrespective of how necessary the re-renders are). Also please remember that
codesandbox uses the development version of React which gives you a really
nice development experience, but performs WAY slower than the production
version of React.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;And this isn&amp;#x27;t just something that&amp;#x27;s useful at the top-level of your app either.
This could be applied to your app anywhere it makes sense. What I like about
this is that
&lt;a href="https://twitter.com/dan_abramov/status/1143201204094341120"&gt;&amp;quot;It&amp;#x27;s both natural for composition &lt;em&gt;and&lt;/em&gt; acts as an optimization opportunity.&amp;quot;&lt;/a&gt;
(that was Dan). So I do this naturally and get the perf benefits for free. And
that&amp;#x27;s what I&amp;#x27;ve always loved about React. &lt;strong&gt;React is written so that idiomatic
React apps are fast by default, and then React provides optimization helpers for
you to use as escape hatches.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Good luck!&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;I want to add a note that if you&amp;#x27;re using legacy context, you wont be able to
get this optimization,
&lt;a href="https://github.com/facebook/react/blob/d420d2ccb6223a66d5e8fe824ac0d31ed5bf87a1/packages/react-reconciler/src/ReactFiberBeginWork.js#L2576"&gt;as React has a special case for that here&lt;/a&gt;,
so people concerned about performance should probably migrate from legacy
context.&lt;/p&gt;&lt;/blockquote&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/optimize-react-re-renders"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Colocation]]></title>
<description><![CDATA[We all want to have codebases that are easy to maintain, so we start out with
the best of intentions to make our codebase (or our corner of the codebase)
maintainable and easy to understand. Over time, as a codebase grows, it can
become more and more…]]></description>
<link>https://kentcdodds.com/blog/colocation</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/colocation</guid>
<pubDate>Mon, 17 Jun 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;We all want to have codebases that are easy to maintain, so we start out with
the best of intentions to make our codebase (or our corner of the codebase)
maintainable and easy to understand. Over time, as a codebase grows, it can
become more and more difficult to manage dependencies (JS, CSS, images, etc.).
As projects grow, an increasing amount of your codebase becomes &amp;quot;tribal
knowledge&amp;quot; (knowledge that only you or a few others are privy to) and this sort
of knowledge contributes to &amp;quot;technical debt&amp;quot; (whether that term is accurate or
&lt;a href="https://twitter.com/ryanflorence/status/747983065738153985"&gt;not&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;I like to keep my codebases manageable for not only me (the one who wrote it),
but also my teammates, future maintainers, and myself in 6 months. I think we
can all agree that this is a great ideal that we should strive for in our
codebases. There are a lot of different tools and techniques at our disposal to
accomplish this.&lt;/p&gt;&lt;h2&gt;Let&amp;#x27;s talk about Code Comments&lt;/h2&gt;&lt;p&gt;I don&amp;#x27;t want to discuss whether to comment your code (you should) and what your
comments should be about (You explain why you&amp;#x27;re doing something unexpected in
the comments so people coming after can understand the decisions that were made
which resulted in the unexpected or odd code). (Ok, maybe I did want to talk
about that a little). Instead I want to focus on where those code comments are
placed. We generally &amp;quot;co-locate&amp;quot; these comments with the code they&amp;#x27;re explaining
by putting it as close as possible to the relevant code.&lt;/p&gt;&lt;p&gt;Consider for a minute, if we did this differently. What if we place those
comments in a totally separate file. A massive &lt;code&gt;DOCUMENTATION.md&lt;/code&gt; file or
perhaps even a &lt;code&gt;docs/&lt;/code&gt; directory that maps back to our &lt;code&gt;src/&lt;/code&gt; directory. Sound
like fun to you? Yeah, not to me either. There would be some serious problems
we&amp;#x27;d encounter by not co-locating our comments with the code it&amp;#x27;s explaining.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Maintainability:&lt;/strong&gt; They&amp;#x27;d get out of sync or out of date quicker (than they
already do). We&amp;#x27;d move or delete a &lt;code&gt;src/&lt;/code&gt; file without updating the
corresponding &lt;code&gt;docs/&lt;/code&gt; file.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Applicability:&lt;/strong&gt; People looking at the code in &lt;code&gt;src/&lt;/code&gt; might miss an
important comment in &lt;code&gt;docs/&lt;/code&gt; or not comment their own code because they don&amp;#x27;t
realize that there&amp;#x27;s an existing &lt;code&gt;docs/&lt;/code&gt; file for the &lt;code&gt;src/&lt;/code&gt; file they&amp;#x27;re
editing.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Ease of use:&lt;/strong&gt; Context switching from one location to the next would be a
challenge with this kind of a set up as well. Having to deal with multiple
locations for files could make it difficult to ensure you have everything you
need to maintain a component.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;We could definitely come up with a convention for this kind of code commenting
style, but why would we want to? Isn&amp;#x27;t it simpler to keep the comments
co-located with the code they&amp;#x27;re explaining?&lt;/p&gt;&lt;h2&gt;So what?&lt;/h2&gt;&lt;p&gt;Now, you&amp;#x27;re probably thinking to yourself: &amp;quot;Yeah, duh, this is why nobody does
this &lt;code&gt;docs/&lt;/code&gt; thing and everyone just co-locates their comments with the code.
That&amp;#x27;s obvious. What&amp;#x27;s your point?&amp;quot; My point is that the benefits of co-location
are everywhere.&lt;/p&gt;&lt;h3&gt;HTML/View&lt;/h3&gt;&lt;p&gt;Take HTML for example. All the benefits of co-locating our comments translate
over to our templates as well. Before modern frameworks like React, you&amp;#x27;d have
your view logic and your view templates in totally separate directories. This
falls prey to the same problems described above. These days it&amp;#x27;s far more common
to put these things &lt;strong&gt;in the exact same file&lt;/strong&gt; with React and Vue for example.
With Angular if it&amp;#x27;s not in the same file, the template file is at least right
next to the JS file with which it is associated.&lt;/p&gt;&lt;h3&gt;CSS&lt;/h3&gt;&lt;p&gt;Another concept this applies well to is CSS. I&amp;#x27;m not going to argue with you
about the merits of CSS-in-JS (it&amp;#x27;s fantastic), but the benefits are out of this
world.
&lt;a href="https://medium.com/seek-blog/a-unified-styling-language-d0c208de2660"&gt;Learn more here&lt;/a&gt;.&lt;/p&gt;&lt;h3&gt;Tests&lt;/h3&gt;&lt;p&gt;This concept of file co-location applies great to unit tests as well. How common
is it to find a project with a &lt;code&gt;src/&lt;/code&gt; directory and a &lt;code&gt;test/&lt;/code&gt; directory filled
with unit tests that attempts to mirror the &lt;code&gt;src/&lt;/code&gt; directory? All the pitfalls
described above apply here as well. I probably wouldn&amp;#x27;t go as far as putting the
unit tests in the exact same file, but I don&amp;#x27;t totally rule that out as an
interesting idea either (the implementation is left as an exercise to the
reader).&lt;/p&gt;&lt;p&gt;To help enable a more maintainable codebase, we should co-locate our tests files
with the file or group of files they are testing. This ensures that when new
people (or myself in 6 months) come to the code, they can see immediately that
the module is tested and use those tests as a reference to learn about the
module. When they make changes, it reminds them to update (add/remove/modify)
the tests to account for their changes.&lt;/p&gt;&lt;h3&gt;State&lt;/h3&gt;&lt;p&gt;Application/Component state experiences the same benefits. The more
disconnected/indirect your state is from the UI that&amp;#x27;s using it, the harder it
is to maintain. Localizing state has even more benefits than maintainability, it
also improves the performance of your application. A state change in one corner
of your application component tree will re-render a lot fewer components than a
state change at the top of the tree. Localize your state.&lt;/p&gt;&lt;h3&gt;&amp;quot;Reusable&amp;quot; utility files&lt;/h3&gt;&lt;p&gt;This applies to &amp;quot;utility&amp;quot; files and functions as well. Imagine you&amp;#x27;re writing a
component and see a nice bit of code that could be extracted into its own
function. You extract it and think: &amp;quot;Huh... I&amp;#x27;ll bet a lot of people could use
this.&amp;quot; So you pull it out and put it into your app&amp;#x27;s &lt;code&gt;utils/&lt;/code&gt; directory and move
on with your life.&lt;/p&gt;&lt;p&gt;Later, your component is deleted, but the utility you wrote is out of sight, out
of mind and it remains (along with its tests) because the person who deleted it
assumed it was more widely used. Over the years, engineers work hard to make
sure that the function and its tests continue to run and function properly
without even realizing that it&amp;#x27;s no longer needed at all. Wasted effort and
cognitive load.&lt;/p&gt;&lt;p&gt;If instead you had just left that function directly in the file that used it,
the story would be completely different. I&amp;#x27;m not saying don&amp;#x27;t bother unit
testing complex utility functions (please do), but keeping them closer to where
they&amp;#x27;re needed helps you avoid problems.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;And for heaven&amp;#x27;s sake,
&lt;a href="https://github.com/yannickcr/eslint-plugin-react/blob/e6b4c33a1db4cc94c3e9223b09fb92b1dbddc00d/docs/rules/no-multi-comp.md"&gt;please DELETE THIS ESLINT RULE&lt;/a&gt;
and all rules like it.&lt;/p&gt;&lt;/blockquote&gt;&lt;h2&gt;The principle&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;The concept of co-location can be boiled down to this fundamental principle:&lt;/strong&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Place code as close to where it&amp;#x27;s relevant as possible&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;You might also say: &amp;quot;Things that change together should be located as close as
reasonable.&amp;quot; (&lt;a href="https://twitter.com/dan_abramov"&gt;Dan Abramov&lt;/a&gt; said something like
this to me once).&lt;/p&gt;&lt;h2&gt;Open Source made easy(-er)&lt;/h2&gt;&lt;p&gt;Aside from avoiding the problems discussed earlier, there are other benefits to
structuring your projects this way. Taking a component and turning it into an
open source project is often as simple as copy/pasting the folder to another
project and publishing that to npm. Then you just install it in your project and
update your require/import statements and you&amp;#x27;re good to go.&lt;/p&gt;&lt;h2&gt;Exceptions&lt;/h2&gt;&lt;p&gt;Sure there&amp;#x27;s a good argument for documentation that spans the whole or part of a
system and how things integrate together. And where would you put integration or
end-to-end tests that span across components? &lt;em&gt;You might think those are
exceptions&lt;/em&gt;, but they can actually subscribe nicely to the principle mentioned
above&lt;/p&gt;&lt;p&gt;If I have a part of my app associated with user authentication and I want to
document that flow, I can put a &lt;em&gt;README.md&lt;/em&gt; file in the folder that has all of
the modules associated with user authentication. If I need to write integration
tests for that flow, I could place the file for those tests in that same folder.&lt;/p&gt;&lt;p&gt;For end-to-end tests, those generally make more sense to go at the root of the
project. They span beyond the project itself and into other parts of the system,
so it makes sense to me for those to be in a separate directory. They don&amp;#x27;t
really map to the &lt;code&gt;src/&lt;/code&gt; files. In fact, E2E tests don&amp;#x27;t really care how the
&lt;code&gt;src/&lt;/code&gt; is organized at all. Refactoring and moving around files in the &lt;code&gt;src/&lt;/code&gt;
directory should not necessitate changing the E2E tests at all.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;Our goal here is to build software that is as simple to maintain as possible.
The same benefits of &lt;strong&gt;maintainability&lt;/strong&gt;, &lt;strong&gt;applicability&lt;/strong&gt;, and &lt;strong&gt;ease of use&lt;/strong&gt;
we get from co-locating our comments we get by co-location of other things as
well. If you&amp;#x27;ve never tried it out, I recommend you give it a shot.&lt;/p&gt;&lt;p&gt;P.S. If you&amp;#x27;re concerned about violating &amp;quot;separation of concerns&amp;quot; I recommend
you check out &lt;a href="https://youtu.be/x7cQ3mrcKaY"&gt;this talk&lt;/a&gt; by
&lt;a href="https://twitter.com/floydophone"&gt;Pete Hunt&lt;/a&gt; and re-evaluate what that means 😀.&lt;/p&gt;&lt;p&gt;P.P.S. I should also note that this applies great to images and really any other
resource as well. And when you use a tool like
&lt;a href="https://webpack.js.org"&gt;webpack&lt;/a&gt;, co-locating those resources is crazy easy
too. Honestly, this is one of the core value propositions of webpack IMO.&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/colocation"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[When to useMemo and useCallback]]></title>
<description><![CDATA[Current Available Translations: Korean Here's a candy dispenser: Here's how it's implemented: Now I want to ask you a question and I want you to think hard about it before
moving forward. I'm going to make a change to this and I want you to tell me…]]></description>
<link>https://kentcdodds.com/blog/usememo-and-usecallback</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/usememo-and-usecallback</guid>
<pubDate>Tue, 04 Jun 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;Current Available Translations:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://ideveloper2.dev/blog/2019-06-14--when-to-use-memo-and-use-callback"&gt;Korean&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Here&amp;#x27;s a candy dispenser:&lt;/p&gt;&lt;div style="background:white;padding:20px;border:2px solid black;border-radius:5px;margin-bottom:20px"&gt;&lt;div&gt;&lt;h1&gt;Candy Dispenser&lt;/h1&gt;&lt;div&gt;&lt;div&gt;Available Candy&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;button&gt;grab&lt;/button&gt; snickers&lt;/li&gt;&lt;li&gt;&lt;button&gt;grab&lt;/button&gt; skittles&lt;/li&gt;&lt;li&gt;&lt;button&gt;grab&lt;/button&gt; twix&lt;/li&gt;&lt;li&gt;&lt;button&gt;grab&lt;/button&gt; milky way&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Here&amp;#x27;s how it&amp;#x27;s implemented:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;function CandyDispenser() {
const initialCandies = [&amp;#x27;snickers&amp;#x27;, &amp;#x27;skittles&amp;#x27;, &amp;#x27;twix&amp;#x27;, &amp;#x27;milky way&amp;#x27;]
const [candies, setCandies] = React.useState(initialCandies)
const dispense = candy =&amp;gt; {
setCandies(allCandies =&amp;gt; allCandies.filter(c =&amp;gt; c !== candy))
}
return (
&amp;lt;div&amp;gt;
&amp;lt;h1&amp;gt;Candy Dispenser&amp;lt;/h1&amp;gt;
&amp;lt;div&amp;gt;
&amp;lt;div&amp;gt;Available Candy&amp;lt;/div&amp;gt;
{candies.length === 0 ? (
&amp;lt;button onClick={() =&amp;gt; setCandies(initialCandies)}&amp;gt;refill&amp;lt;/button&amp;gt;
) : (
&amp;lt;ul&amp;gt;
{candies.map(candy =&amp;gt; (
&amp;lt;li key={candy}&amp;gt;
&amp;lt;button onClick={() =&amp;gt; dispense(candy)}&amp;gt;grab&amp;lt;/button&amp;gt; {candy}
&amp;lt;/li&amp;gt;
))}
&amp;lt;/ul&amp;gt;
)}
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now I want to ask you a question and I want you to think hard about it before
moving forward. I&amp;#x27;m going to make a change to this and I want you to tell me
which will have the better performance characteristics.&lt;/p&gt;&lt;p&gt;The only thing I&amp;#x27;m going to change is wrap the &lt;code&gt;dispense&lt;/code&gt; function inside
&lt;code&gt;React.useCallback&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const dispense = React.useCallback(candy =&amp;gt; {
setCandies(allCandies =&amp;gt; allCandies.filter(c =&amp;gt; c !== candy))
}, [])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here&amp;#x27;s the original again:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const dispense = candy =&amp;gt; {
setCandies(allCandies =&amp;gt; allCandies.filter(c =&amp;gt; c !== candy))
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So here&amp;#x27;s my question, in this specific case, which of these is better for
performance? Go ahead and submit your guess (this is not recorded anywhere):&lt;/p&gt;&lt;div style="margin:20px 0 50px 0"&gt;&lt;div&gt;&lt;div style="margin-bottom:10px"&gt;&lt;button&gt;original&lt;/button&gt;&lt;/div&gt;&lt;div&gt;&lt;button&gt;useCallback&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;p&gt;Let me give you some space to not spoil the answer for you...&lt;/p&gt;&lt;/blockquote&gt;&lt;div style="height:400px"&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;p&gt;Keep scrolling... You did answer, didn&amp;#x27;t you?&lt;/p&gt;&lt;/blockquote&gt;&lt;div style="height:400px"&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;p&gt;There, that should do it...&lt;/p&gt;&lt;/blockquote&gt;&lt;h2&gt;Why is &lt;code&gt;useCallback&lt;/code&gt; worse?!&lt;/h2&gt;&lt;p&gt;We hear a lot that you should use &lt;code&gt;React.useCallback&lt;/code&gt; to improve performance and
that &amp;quot;inline functions can be problematic for performance,&amp;quot; so how could it ever
be better to &lt;em&gt;not&lt;/em&gt; &lt;code&gt;useCallback&lt;/code&gt;?&lt;/p&gt;&lt;p&gt;Just take a step back from our specific example, and even from React and
consider this: &lt;strong&gt;Every line of code which is executed comes with a cost.&lt;/strong&gt; Let
me refactor the &lt;code&gt;useCallback&lt;/code&gt; example a bit (no actual changes, just moving
things around) to illustrate things more clearly:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const dispense = candy =&amp;gt; {
setCandies(allCandies =&amp;gt; allCandies.filter(c =&amp;gt; c !== candy))
}
const dispenseCallback = React.useCallback(dispense, [])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And here&amp;#x27;s the original again:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const dispense = candy =&amp;gt; {
setCandies(allCandies =&amp;gt; allCandies.filter(c =&amp;gt; c !== candy))
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Notice anything about these? Let&amp;#x27;s look at the diff:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-diff"&gt; const dispense = candy =&amp;gt; {
setCandies(allCandies =&amp;gt; allCandies.filter(c =&amp;gt; c !== candy))
}
+ const dispenseCallback = React.useCallback(dispense, [])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Yeah, they&amp;#x27;re &lt;em&gt;exactly&lt;/em&gt; the same except the &lt;code&gt;useCallback&lt;/code&gt; version is doing
&lt;em&gt;more&lt;/em&gt; work. Not only do we have to define the function, but we also have to
define an array (&lt;code&gt;[]&lt;/code&gt;) &lt;em&gt;and&lt;/em&gt; call the &lt;code&gt;React.useCallback&lt;/code&gt; which itself is
setting properties/running through logical expressions etc.&lt;/p&gt;&lt;p&gt;So in &lt;em&gt;both&lt;/em&gt; cases JavaScript must allocate memory for the function definition
on every render and depending on how &lt;code&gt;useCallback&lt;/code&gt; is implemented, you may get
&lt;em&gt;more&lt;/em&gt; allocation for function definitions (this is actually not the case, but
the point still stands). This is what I was trying to get across with my twitter
poll here:&lt;/p&gt;&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;Assuming this code appears in a React function component, how many function allocations are happening with this code on each render?&lt;br/&gt;&lt;br/&gt;const a = () =&amp;gt; {}&lt;br/&gt;&lt;br/&gt;And how many are happening with this code?&lt;br/&gt;&lt;br/&gt;const a = useCallback(() =&amp;gt; {}, [])&lt;/p&gt;— Kent C. Dodds (@kentcdodds) &lt;a href="https://twitter.com/kentcdodds/status/1135943012410830848"&gt;June 4, 2019&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Granted, I had several people tell me that was worded poorly, so my apologies
if you got the wrong answer but actually knew the correct answer.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I&amp;#x27;d like to mention also that on the second render of the component, the
original &lt;code&gt;dispense&lt;/code&gt; function gets garbage collected (freeing up memory space)
and then a new one is created. However with &lt;code&gt;useCallback&lt;/code&gt; the original
&lt;code&gt;dispense&lt;/code&gt; function wont get garbage collected and a new one is created, so
you&amp;#x27;re worse-off from a memory perspective as well.&lt;/p&gt;&lt;p&gt;As a related note, if you have dependencies then it&amp;#x27;s quite possible React is
hanging on to a reference to previous functions because memoization typically
means that we keep copies of old values to return in the event we get the same
dependencies as given previously. The especially astute of you will notice that
this means React also has to hang on to a reference to the dependencies for this
equality check (which incidentally is probably happening anyway thanks to your
closure, but it&amp;#x27;s something worth mentioning anyway).&lt;/p&gt;&lt;h2&gt;How is &lt;code&gt;useMemo&lt;/code&gt; different, but similar?&lt;/h2&gt;&lt;p&gt;&lt;code&gt;useMemo&lt;/code&gt; is similar to &lt;code&gt;useCallback&lt;/code&gt; except it allows you to apply memoization
to any value type (not just functions). It does this by accepting a function
which returns the value and then that function is &lt;em&gt;only&lt;/em&gt; called when the value
needs to be retrieved (which typically will only happen once each time an
element in the dependencies array changes between renders).&lt;/p&gt;&lt;p&gt;So, if I didn&amp;#x27;t want to initialize that array of &lt;code&gt;initialCandies&lt;/code&gt; every render,
I could make this change:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-diff"&gt;- const initialCandies = [&amp;#x27;snickers&amp;#x27;, &amp;#x27;skittles&amp;#x27;, &amp;#x27;twix&amp;#x27;, &amp;#x27;milky way&amp;#x27;]
+ const initialCandies = React.useMemo(
+ () =&amp;gt; [&amp;#x27;snickers&amp;#x27;, &amp;#x27;skittles&amp;#x27;, &amp;#x27;twix&amp;#x27;, &amp;#x27;milky way&amp;#x27;],
+ [],
+ )
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And I would avoid that problem, but the savings would be so minimal that the
cost of making the code more complex just isn&amp;#x27;t worth it. In fact, it&amp;#x27;s probably
worse to use &lt;code&gt;useMemo&lt;/code&gt; for this as well because again we&amp;#x27;re making a function
call and that code is doing property assignments etc.&lt;/p&gt;&lt;p&gt;In this particular scenario, what would be even better is to make this change:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-diff"&gt;+ const initialCandies = [&amp;#x27;snickers&amp;#x27;, &amp;#x27;skittles&amp;#x27;, &amp;#x27;twix&amp;#x27;, &amp;#x27;milky way&amp;#x27;]
function CandyDispenser() {
- const initialCandies = [&amp;#x27;snickers&amp;#x27;, &amp;#x27;skittles&amp;#x27;, &amp;#x27;twix&amp;#x27;, &amp;#x27;milky way&amp;#x27;]
const [candies, setCandies] = React.useState(initialCandies)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But sometimes you don&amp;#x27;t have that luxury because the value is either derived
from &lt;code&gt;props&lt;/code&gt; or other variables initialized within the body of the function.&lt;/p&gt;&lt;p&gt;The point is that it doesn&amp;#x27;t matter either way. The benefits of optimizing that
code is so minuscule that your time would be WAY better spent worrying about
making your product better.&lt;/p&gt;&lt;h2&gt;What&amp;#x27;s the point?&lt;/h2&gt;&lt;p&gt;The point is this:&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Performance optimizations are not free. They ALWAYS come with a cost but do
NOT always come with a benefit to offset that cost.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Therefore, &lt;em&gt;optimize responsibly&lt;/em&gt;.&lt;/p&gt;&lt;h2&gt;So when &lt;em&gt;should&lt;/em&gt; I &lt;code&gt;useMemo&lt;/code&gt; and &lt;code&gt;useCallback&lt;/code&gt;?&lt;/h2&gt;&lt;p&gt;There are specific reasons both of these hooks are built-into React:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Referential equality&lt;/li&gt;&lt;li&gt;Computationally expensive calculations&lt;/li&gt;&lt;/ol&gt;&lt;h2&gt;Referential equality&lt;/h2&gt;&lt;p&gt;If you&amp;#x27;re new to JavaScript/programming, it wont take long before you learn why
this is the case:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;true === true // true
false === false // true
1 === 1 // true
&amp;#x27;a&amp;#x27; === &amp;#x27;a&amp;#x27; // true
{} === {} // false
[] === [] // false
() =&amp;gt; {} === () =&amp;gt; {} // false
const z = {}
z === z // true
// NOTE: React actually uses Object.is, but it&amp;#x27;s very similar to ===
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I&amp;#x27;m not going to go too deep into this, but suffice it to say when you define an
object inside your React function component, it is &lt;em&gt;not&lt;/em&gt; going to be
referentially equal to the last time that same object was defined (even if it
has all the same properties with all the same values).&lt;/p&gt;&lt;p&gt;There are two situations where referential equality matters in React, let&amp;#x27;s go
through them one at a time.&lt;/p&gt;&lt;h3&gt;Dependencies lists&lt;/h3&gt;&lt;p&gt;Let&amp;#x27;s review an example.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Warning, you&amp;#x27;re about to see some seriously contrived code. Please don&amp;#x27;t
nit-pick that and just focus on the concepts please, thank you.&lt;/p&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;function Foo({bar, baz}) {
const options = {bar, baz}
React.useEffect(() =&amp;gt; {
buzz(options)
}, [options]) // we want this to re-run if bar or baz change
return &amp;lt;div&amp;gt;foobar&amp;lt;/div&amp;gt;
}
function Blub() {
return &amp;lt;Foo bar=&amp;quot;bar value&amp;quot; baz={3} /&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The reason this is problematic is because &lt;code&gt;useEffect&lt;/code&gt; is going to do a
referential equality check on &lt;code&gt;options&lt;/code&gt; between every render, and thanks to the
way JavaScript works, &lt;code&gt;options&lt;/code&gt; will be new every time so when React tests
whether &lt;code&gt;options&lt;/code&gt; changed between renders it&amp;#x27;ll always evaluate to &lt;code&gt;true&lt;/code&gt;,
meaning the &lt;code&gt;useEffect&lt;/code&gt; callback will be called after every render rather than
only when &lt;code&gt;bar&lt;/code&gt; and &lt;code&gt;baz&lt;/code&gt; change.&lt;/p&gt;&lt;p&gt;There are two things we can do to fix this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;// option 1
function Foo({bar, baz}) {
React.useEffect(() =&amp;gt; {
const options = {bar, baz}
buzz(options)
}, [bar, baz]) // we want this to re-run if bar or baz change
return &amp;lt;div&amp;gt;foobar&amp;lt;/div&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That&amp;#x27;s a great option and if this were a real thing that&amp;#x27;s how I&amp;#x27;d fix this.&lt;/p&gt;&lt;p&gt;But there&amp;#x27;s one situation when this isn&amp;#x27;t a practical solution: If &lt;code&gt;bar&lt;/code&gt; or
&lt;code&gt;baz&lt;/code&gt; are (non-primitive) objects/arrays/functions/etc:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;function Blub() {
const bar = () =&amp;gt; {}
const baz = [1, 2, 3]
return &amp;lt;Foo bar={bar} baz={baz} /&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is precisely the reason why &lt;code&gt;useCallback&lt;/code&gt; and &lt;code&gt;useMemo&lt;/code&gt; exist. So here&amp;#x27;s
how you&amp;#x27;d fix that (all together now):&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;function Foo({bar, baz}) {
React.useEffect(() =&amp;gt; {
const options = {bar, baz}
buzz(options)
}, [bar, baz])
return &amp;lt;div&amp;gt;foobar&amp;lt;/div&amp;gt;
}
function Blub() {
const bar = React.useCallback(() =&amp;gt; {}, [])
const baz = React.useMemo(() =&amp;gt; [1, 2, 3], [])
return &amp;lt;Foo bar={bar} baz={baz} /&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;Note that this same thing applies for the dependencies array passed to
&lt;code&gt;useEffect&lt;/code&gt;, &lt;code&gt;useLayoutEffect&lt;/code&gt;, &lt;code&gt;useCallback&lt;/code&gt;, and &lt;code&gt;useMemo&lt;/code&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;h3&gt;&lt;code&gt;React.memo&lt;/code&gt; (and friends)&lt;/h3&gt;&lt;blockquote&gt;&lt;p&gt;Warning, you&amp;#x27;re about to see some more contrived code. Please be advised to
not nit-pick this either but focus on the concepts, thanks.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Check this out:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;function CountButton({onClick, count}) {
return &amp;lt;button onClick={onClick}&amp;gt;{count}&amp;lt;/button&amp;gt;
}
function DualCounter() {
const [count1, setCount1] = React.useState(0)
const increment1 = () =&amp;gt; setCount1(c =&amp;gt; c + 1)
const [count2, setCount2] = React.useState(0)
const increment2 = () =&amp;gt; setCount2(c =&amp;gt; c + 1)
return (
&amp;lt;&amp;gt;
&amp;lt;CountButton count={count1} onClick={increment1} /&amp;gt;
&amp;lt;CountButton count={count2} onClick={increment2} /&amp;gt;
&amp;lt;/&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Every time you click on either of those buttons, the &lt;code&gt;DualCounter&lt;/code&gt;&amp;#x27;s state
changes and therefore re-renders which in turn will re-render both of the
&lt;code&gt;CountButton&lt;/code&gt;s. However, the only one that &lt;em&gt;actually&lt;/em&gt; needs to re-render is the
one that was clicked right? So if you click the first one, the second one gets
re-rendered, but nothing changes. We call this an &amp;quot;unnecessary re-render.&amp;quot;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;MOST OF THE TIME YOU SHOULD NOT BOTHER OPTIMIZING UNNECESSARY RERENDERS.&lt;/strong&gt;
React is VERY fast and there are so many things I can think of for you to do
with your time that would be better than optimizing things like this. In fact,
the need to optimize stuff with what I&amp;#x27;m about to show you is so rare that I&amp;#x27;ve
literally &lt;em&gt;never&lt;/em&gt; needed to do it in the 3 years I worked on PayPal products and
the even longer time that I&amp;#x27;ve been working with React.&lt;/p&gt;&lt;p&gt;However, there are situations when rendering can take a substantial amount of
time (think highly interactive Graphs/Charts/Animations/etc.). Thanks to the
pragmatistic nature of React, there&amp;#x27;s an escape hatch:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;const CountButton = React.memo(function CountButton({onClick, count}) {
return &amp;lt;button onClick={onClick}&amp;gt;{count}&amp;lt;/button&amp;gt;
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now React will only re-render &lt;code&gt;CountButton&lt;/code&gt; when it&amp;#x27;s props change! Woo! But
we&amp;#x27;re not done yet. Remember that whole referential equality thing? In the
&lt;code&gt;DualCounter&lt;/code&gt; component, we&amp;#x27;re defining the &lt;code&gt;increment1&lt;/code&gt; and &lt;code&gt;increment2&lt;/code&gt;
functions within the component functions which means every time &lt;code&gt;DualCounter&lt;/code&gt; is
re-rendered, those functions will be new and therefore React will re-render both
of the &lt;code&gt;CountButton&lt;/code&gt;s anyway.&lt;/p&gt;&lt;p&gt;So this is the other situation where &lt;code&gt;useCallback&lt;/code&gt; and &lt;code&gt;useMemo&lt;/code&gt; can be of help:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx" metastring="{7, 10}"&gt;const CountButton = React.memo(function CountButton({onClick, count}) {
return &amp;lt;button onClick={onClick}&amp;gt;{count}&amp;lt;/button&amp;gt;
})
function DualCounter() {
const [count1, setCount1] = React.useState(0)
const increment1 = React.useCallback(() =&amp;gt; setCount1(c =&amp;gt; c + 1), [])
const [count2, setCount2] = React.useState(0)
const increment2 = React.useCallback(() =&amp;gt; setCount2(c =&amp;gt; c + 1), [])
return (
&amp;lt;&amp;gt;
&amp;lt;CountButton count={count1} onClick={increment1} /&amp;gt;
&amp;lt;CountButton count={count2} onClick={increment2} /&amp;gt;
&amp;lt;/&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we can avoid the so-called &amp;quot;unnecessary re-renders&amp;quot; of &lt;code&gt;CountButton&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;I would like to re-iterate that I strongly advise against using &lt;code&gt;React.memo&lt;/code&gt; (or
it&amp;#x27;s friends &lt;code&gt;PureComponent&lt;/code&gt; and &lt;code&gt;shouldComponentUpdate&lt;/code&gt;) without measuring
because those optimizations come with a cost and you need to make sure you know
what that cost will be as well as the associated benefit so you can determine
whether it will actually be helpful (and not harmful) in your case, and as we
observe above &lt;strong&gt;it can be tricky to get right all the time so you may not be
reaping any benefits at all anyway.&lt;/strong&gt;&lt;/p&gt;&lt;h2&gt;Computationally expensive calculations&lt;/h2&gt;&lt;p&gt;This is the other reason that &lt;code&gt;useMemo&lt;/code&gt; is a built-in hook for React (note that
this one does not apply to &lt;code&gt;useCallback&lt;/code&gt;). The benefit to &lt;code&gt;useMemo&lt;/code&gt; is that you
can take a value like:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const a = {b: props.b}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And get it lazily:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const a = React.useMemo(() =&amp;gt; ({b: props.b}), [props.b])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This isn&amp;#x27;t really useful for that case above, but imagine that you&amp;#x27;ve got a
function that synchronously calculates a value which is computationally
expensive to calculate (I mean how many apps actually need to
&lt;a href="https://developer.mozilla.org/en-US/docs/Tools/Performance/Scenarios/Intensive_JavaScript"&gt;calculate prime numbers like this&lt;/a&gt;
ever, but that&amp;#x27;s an example):&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;function RenderPrimes({iterations, multiplier}) {
const primes = calculatePrimes(iterations, multiplier)
return &amp;lt;div&amp;gt;Primes! {primes}&amp;lt;/div&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That could be pretty slow given the right &lt;code&gt;iterations&lt;/code&gt; or &lt;code&gt;multiplier&lt;/code&gt; and
there&amp;#x27;s not too much you can do about that specifically. You can&amp;#x27;t automagically
make your user&amp;#x27;s hardware faster. But you &lt;em&gt;can&lt;/em&gt; make it so you never have to
calculate the same value twice in a row, which is what &lt;code&gt;useMemo&lt;/code&gt; will do for
you:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;function RenderPrimes({iterations, multiplier}) {
const primes = React.useMemo(() =&amp;gt; calculatePrimes(iterations, multiplier), [
iterations,
multiplier,
])
return &amp;lt;div&amp;gt;Primes! {primes}&amp;lt;/div&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The reason this works is because even though you&amp;#x27;re defining the function to
calculate the primes on every render (which is VERY fast), React is only calling
that function when the value is needed. On top of that React also stores
previous values given the inputs and will return the previous value given the
same previous inputs. That&amp;#x27;s memoization at work.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;I&amp;#x27;d just like to wrap this up by saying that every abstraction (and performance
optimization) comes at a cost. Apply
&lt;a href="https://kentcdodds.com/blog/aha-programming"&gt;the AHA Programming principle&lt;/a&gt; and wait until the
abstraction/optimization is screaming at you before applying it and you&amp;#x27;ll save
yourself from incurring the costs without reaping the benefit.&lt;/p&gt;&lt;p&gt;Specifically the cost for &lt;code&gt;useCallback&lt;/code&gt; and &lt;code&gt;useMemo&lt;/code&gt; are that you make the code
more complex for your co-workers, you could make a mistake in the dependencies
array, and you&amp;#x27;re potentially making performance worse by invoking the built-in
hooks and preventing dependencies and memoized values from being garbage
collected. Those are all fine costs to incur if you get the performance benefits
necessary, but &lt;strong&gt;it&amp;#x27;s best to measure first.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Related reading:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;React FAQ:
&lt;a href="https://reactjs.org/docs/hooks-faq.html#are-hooks-slow-because-of-creating-functions-in-render"&gt;&amp;quot;Are Hooks slow because of creating functions in render?&amp;quot;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://twitter.com/ryanflorence"&gt;Ryan Florence&lt;/a&gt;:
&lt;a href="https://reacttraining.com/blog/react-inline-functions-and-performance"&gt;React, Inline Functions, and Performance&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;P.S. If you&amp;#x27;re among the few who worry about the move to hooks and that it
forces us to define functions within our function components where we used to
define functions as methods on our classes, I would invite you to consider the
fact that we&amp;#x27;ve been defining methods in the render phase of our components
since day one... For example:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;class FavoriteNumbers extends React.Component {
render() {
return (
&amp;lt;ul&amp;gt;
{this.props.favoriteNumbers.map(number =&amp;gt; (
// TADA! This is a function defined in the render method!
// Hooks did not introduce this concept.
// We&amp;#x27;ve been doing this all along.
&amp;lt;li key={number}&amp;gt;{number}&amp;lt;/li&amp;gt;
))}
&amp;lt;/ul&amp;gt;
)
}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/usememo-and-usecallback"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[What open source project should I contribute to?]]></title>
<description><![CDATA[This is a question I've had countless times: https://twitter.com/sarna_pranu/status/672438850724175872 Pranu first pull request soon after tweeting this https://twitter.com/geraldchecka/status/670445392706736128 And in direct messages, emails, etc…]]></description>
<link>https://kentcdodds.com/blog/what-open-source-project-should-i-contribute-to</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/what-open-source-project-should-i-contribute-to</guid>
<pubDate>Mon, 03 Jun 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;This is a question I&amp;#x27;ve had countless times:&lt;/p&gt;&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;&lt;a href="https://twitter.com/kentcdodds"&gt;@kentcdodds&lt;/a&gt; hey Kent! went through your post on Get started contributing to open source, Wanting to make some contributions. Guide me master&lt;/p&gt;— Pranu Sarna (@sarna_pranu) &lt;a href="https://twitter.com/sarna_pranu/status/672438850724175872"&gt;December 3, 2015&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;&lt;a href="https://github.com/Automattic/mongoose/pull/3644"&gt;Pranu first pull request soon after tweeting this&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;&lt;a href="https://twitter.com/_ericelliott"&gt;@_ericelliott&lt;/a&gt; &amp;amp; &lt;a href="https://twitter.com/kentcdodds"&gt;@kentcdodds&lt;/a&gt; Can you suggest some frontend repos to contribute to? &lt;a href="https://t.co/WjrLWiRAwT"&gt;https://t.co/WjrLWiRAwT&lt;/a&gt;&lt;/p&gt;— Anvesh (@geraldchecka) &lt;a href="https://twitter.com/geraldchecka/status/670445392706736128"&gt;November 28, 2015&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;&lt;p&gt;And in direct messages, emails, etc. The general gist of it is: &amp;quot;What open
source project can you recommend I start contributing to?&amp;quot; Many of these people
read my &lt;a href="https://kentcdodds.com/blog/first-timers-only"&gt;First Timers Only&lt;/a&gt; post and are hoping to find
a project that is friendly to newcomers
&lt;a href="https://help.github.com/articles/creating-a-pull-request"&gt;making&lt;/a&gt;
&lt;a href="https://help.github.com/articles/using-pull-requests"&gt;pull requests&lt;/a&gt;.&lt;/p&gt;&lt;h2&gt;The Answer&lt;/h2&gt;&lt;p&gt;My silver bullet answer comes from my blog post
&lt;a href="https://kentcdodds.com/blog/open-source-stamina"&gt;Open Source Stamina&lt;/a&gt;:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;You contribute best to something you use regularly&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Where I&amp;#x27;ve found the most satisfaction out of contributing to open source is in
projects that matter to me and (possibly) others. And then contributing to that
project regularly. To do that you need to have an understanding of the use cases
and pains associated with a particular tool or library. This is why I say &lt;em&gt;it&amp;#x27;s
best to contribute to something you use regularly&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;What open source libraries/frameworks/tools do you use regularly? Perhaps you&amp;#x27;re
working with Webpack and feel like a configuration option could be improved or
documented better. Or maybe you&amp;#x27;re working with a React or Vue library that
could use a little polish. One thing&amp;#x27;s certain, whatever you&amp;#x27;re building, you&amp;#x27;re
probably using an open source project or tool that you could personally benefit
from contributing to.&lt;/p&gt;&lt;p&gt;Step 1: Open your &lt;code&gt;package.json&lt;/code&gt; and read through the dependencies you have.
Think back on your experience learning and using that module. Remember
struggling with one of them? Pick that one.&lt;/p&gt;&lt;h2&gt;Contributing&lt;/h2&gt;&lt;p&gt;Once you&amp;#x27;ve found the project you want to contribute to, how do you know what to
contribute? Many projects have
&lt;a href="https://github.com/blog/1184-contributing-guidelines"&gt;a CONTRIBUTING file&lt;/a&gt;.
Look for that first to find instructions for contributing to the project. If
there isn&amp;#x27;t one, there may be instructions in the &lt;code&gt;README&lt;/code&gt; (normally shown on
the homepage of the project). If there aren&amp;#x27;t any such instructions, you might
submit a pull request to add just a skeleton &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; file to start a
conversation about adding one.&lt;/p&gt;&lt;p&gt;Familiarize yourself with the project. Reading documentation is good, but my
favorite way to learn how a project works is by reading the code. My favorite
way to do this is by sticking a &lt;code&gt;debugger&lt;/code&gt; before I call a library function or
when a library calls my function and jumping around the call stack, like this:&lt;/p&gt;&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;If you&amp;#x27;ve not stepped in React code in the debugger, give it a shot, it&amp;#x27;s kinda fun :) &lt;a href="https://t.co/R84yJfjLT8"&gt;https://t.co/R84yJfjLT8&lt;/a&gt; &lt;a href="https://t.co/KEA99HMIVK"&gt;pic.twitter.com/KEA99HMIVK&lt;/a&gt;&lt;/p&gt;— Kent C. Dodds (@kentcdodds) &lt;a href="https://twitter.com/kentcdodds/status/1135687475110670341"&gt;June 3, 2019&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;&lt;p&gt;Step through the code and you&amp;#x27;ll learn a lot about how the framework/library
works. Don&amp;#x27;t worry if you don&amp;#x27;t understand what&amp;#x27;s going on right away. That will
come with time. Keep at it. You can do it! You can do this same thing with
non-browser based tools with your favorite
&lt;a href="https://code.visualstudio.com/docs/editor/debugging"&gt;node debugger&lt;/a&gt; (or add
console.logs).&lt;/p&gt;&lt;p&gt;Once you&amp;#x27;ve figured out the standards and processes for contributing to the
project and familiarized yourself with its inner-workings a bit, you&amp;#x27;ll need to
identify the changes that the project needs. I recommend you look at existing
issues and comment on ones you think are interesting. Work with the
maintainer(s) to identify a good implementation and
&lt;a href="https://help.github.com/articles/creating-a-pull-request"&gt;make your pull request&lt;/a&gt;!&lt;/p&gt;&lt;p&gt;If you have your own idea of a bug fix or a feature you want to implement, I
strongly recommend you run it by the project maintainer(s) in a
&lt;a href="https://guides.github.com/features/issues"&gt;GitHub issue&lt;/a&gt; first. Perhaps they&amp;#x27;ll
say it&amp;#x27;s out of scope for the project or they&amp;#x27;re working on it, or they could
give you some direction. You&amp;#x27;ll waste less time by making sure your pull request
will be accepted before you make it (just like how I was certain my wife would
answer &amp;quot;yes&amp;quot; when I asked her to marry me &lt;em&gt;before&lt;/em&gt; I asked 😃).&lt;/p&gt;&lt;p&gt;&lt;em&gt;Also, see &lt;a href="http://24pullrequests.com/contributing"&gt;this page&lt;/a&gt; for more tips on
contributing.&lt;/em&gt;&lt;/p&gt;&lt;h2&gt;Your First Pull Request&lt;/h2&gt;&lt;p&gt;For your first
&lt;a href="https://help.github.com/articles/using-pull-requests"&gt;pull request&lt;/a&gt;, feel free
to just find a random project out there with a good first timer bug/feature and
try your hand at contributing. Let the project maintainer know that you&amp;#x27;re new
and are wanting some guidance to learn how to get into it. Maybe they&amp;#x27;re too
busy to help, if so, move on and find another project. That first contribution
is the hardest, you may want some help and coaching. The actual code
contribution matters less than learning the process. So find a project or
someone who has time and patience to mentor you.&lt;/p&gt;&lt;p&gt;You might also be interested in watching my &lt;strong&gt;free&lt;/strong&gt; egghead.io course
&lt;a href="https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github"&gt;How to Contribute to an Open Source Project on GitHub&lt;/a&gt;:&lt;/p&gt;&lt;p&gt;&lt;a href="https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github"&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:800px"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:100%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="Course Artwork" title="Course Artwork" src="https://kentcdodds.com/static/0aa5a059d464b7bd7b3912ac9a7d8be9/8ff1e/pull-request-art.png" srcSet="https://kentcdodds.com/static/0aa5a059d464b7bd7b3912ac9a7d8be9/f4a45/pull-request-art.png 259w,https://kentcdodds.com/static/0aa5a059d464b7bd7b3912ac9a7d8be9/ef0f6/pull-request-art.png 518w,https://kentcdodds.com/static/0aa5a059d464b7bd7b3912ac9a7d8be9/8ff1e/pull-request-art.png 800w" sizes="(max-width: 800px) 100vw, 800px"/&gt;
&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;h2&gt;Resources&lt;/h2&gt;&lt;p&gt;Take a look at GitHub&amp;#x27;s issues for issues labeled
&lt;a href="https://github.com/issues?utf8=%E2%9C%93&amp;amp;q=is%3Aopen+is%3Aissue+label%3Afirst-timers-only"&gt;first-timers-only&lt;/a&gt;,
&lt;a href="https://github.com/issues?utf8=%E2%9C%93&amp;amp;q=is%3Aopen+is%3Aissue+label%3A%22good+for+beginners%22+"&gt;good for beginners&lt;/a&gt;,
&lt;a href="https://github.com/issues?utf8=%E2%9C%93&amp;amp;q=is%3Aopen+is%3Aissue+label%3A%22good+first+bug%22+"&gt;good first bug&lt;/a&gt;
(or
&lt;a href="https://github.com/issues?utf8=%E2%9C%93&amp;amp;q=is%3Aopen+is%3Aissue+label%3Agood-first-bug"&gt;good-first-bug&lt;/a&gt;),
or
&lt;a href="https://github.com/issues?utf8=%E2%9C%93&amp;amp;q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+"&gt;help wanted&lt;/a&gt;
(more &lt;a href="https://twitter.com/kentcdodds/status/672873736974897152"&gt;here&lt;/a&gt;... we
&lt;em&gt;need&lt;/em&gt; to standardize on this).&lt;/p&gt;&lt;p&gt;Also, here are good resources for finding simple ways to contribute:&lt;/p&gt;&lt;p&gt;&lt;a href="https://twitter.com/yourfirstpr"&gt;&lt;strong&gt;Your First PR (@yourfirstpr)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="https://twitter.com/first_tmrs_only"&gt;&lt;strong&gt;first-timers-only (@first_tmrs_only)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://24pullrequests.com"&gt;&lt;strong&gt;24 Pull Requests&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://up-for-grabs.net/#"&gt;&lt;strong&gt;Up For Grabs&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="https://github.com/MunGell/awesome-for-beginners"&gt;&lt;strong&gt;MunGell/awesome-for-beginners&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://firstpr.me/#kentcdodds"&gt;My first PR&lt;/a&gt; was to fix a typo in a comment
(&lt;a href="http://firstpr.me"&gt;find yours&lt;/a&gt;). It was super small and it was to a project
that I didn&amp;#x27;t really use all that much (discovered the typo when stepping
through their code in a debugger). It was a great first contribution, even
though I didn&amp;#x27;t really make a lasting impact on the project and I wasn&amp;#x27;t
motivated to continue contributing, it got me over the hump of contributing for
the first time which is the hardest part.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;Contributing to open source
&lt;a href="https://kentcdodds.com/blog/how-getting-into-open-source-has-been-awesome-for-me"&gt;has been awesome for me&lt;/a&gt;
and I highly recommend others to get into it. It&amp;#x27;s really hard getting started,
but once you get over the first contribution, making future contributions is
much easier. It&amp;#x27;s not all roses. The open source community has its warts here
and there. Keep working at it. You&amp;#x27;ll do great! Good luck!&lt;/p&gt;&lt;p&gt;By the way, if you&amp;#x27;re interested in creating your own project, be sure to check
out my series on egghead.io:&lt;/p&gt;&lt;p&gt;&lt;a href="https://egghead.io/series/how-to-write-an-open-source-javascript-library"&gt;&lt;strong&gt;How to Write an Open Source JavaScript Library&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/what-open-source-project-should-i-contribute-to"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Avoid the Test User]]></title>
<description><![CDATA[The two users your UI code has are 1) The end user that's interacting with your
component and 2) the developer rendering your component. Imagine you have the
following UI (taken from my
Advanced React Patterns material): Note: this is not a…]]></description>
<link>https://kentcdodds.com/blog/avoid-the-test-user</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/avoid-the-test-user</guid>
<pubDate>Fri, 24 May 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;The two users your UI code has are 1) The end user that&amp;#x27;s interacting with your
component and 2) the developer rendering your component. Imagine you have the
following UI (taken from my
&lt;a href="https://kentcdodds.com/workshops/advanced-react-patterns"&gt;Advanced React Patterns&lt;/a&gt; material):&lt;/p&gt;&lt;div style="max-width:300px;margin:10px auto 40px auto"&gt;&lt;div style="background-color:#ddd;border-radius:4px;padding:10px"&gt;&lt;form&gt;&lt;div style="margin-bottom:12px"&gt;&lt;label style="display:block" for="username"&gt;Username&lt;/label&gt;&lt;input id="username" name="username" disabled="" readonly="" value="jakiechan" style="width:100%"/&gt;&lt;/div&gt;&lt;div style="margin-bottom:12px"&gt;&lt;label style="display:block" for="tagline"&gt;Tagline&lt;/label&gt;&lt;input id="tagline" name="tagline" value="" style="width:100%"/&gt;&lt;/div&gt;&lt;div style="margin-bottom:12px"&gt;&lt;label style="display:block" for="bio"&gt;Biography&lt;/label&gt;&lt;textarea id="bio" name="bio" style="width:100%"&gt;&lt;/textarea&gt;&lt;/div&gt;&lt;div style="display:flex;justify-content:space-between"&gt;&lt;button type="button" disabled=""&gt;Reset&lt;/button&gt;&lt;button type="submit" disabled=""&gt;✔&lt;/button&gt;&lt;/div&gt;&lt;/form&gt;&lt;/div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;p&gt;Note: this is not a screenshot. You can actually interact with that form.
Hooray for &lt;a href="https://mdxjs.com"&gt;MDX&lt;/a&gt;!&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;The form component here is called &lt;code&gt;&amp;lt;UserSettings /&amp;gt;&lt;/code&gt;. This component exposes a
certain API for the developers rendering it and the users using it.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;The End User&lt;/strong&gt;: Renders a username field (which is disabled because it cannot
be changed), tagline field, and biography field. When the end user changes one
of the values, the reset and submit buttons become enabled. When they click the
reset button the form is reset and when they click the submit button it saves
the user&amp;#x27;s info (showing a loading state while we wait for the request to
finish). (In this demo, if you type &amp;quot;fail&amp;quot; in the tagline or biography then the
request fails and you can see the error state as well).&lt;/p&gt;&lt;p&gt;&lt;strong&gt;The Developer User&lt;/strong&gt;: They render this component within a &lt;code&gt;&amp;lt;UserProvider /&amp;gt;&lt;/code&gt;
so the component can access and update the application &lt;code&gt;user&lt;/code&gt; state and dispatch
which is stored in React context.&lt;/p&gt;&lt;p&gt;These are the only two users that your component should be concerned with. This
component can experience a lot of changes over time. If it makes changes that
alter the developer&amp;#x27;s API or the end user&amp;#x27;s expectations, then additional
changes need to be made. If it changes the API, (like maybe it accepts a user
prop instead of accessing it from context) then the developer user will have to
alter its usage to account for that. If it changes the user experience, then
maybe there will need to be release notes explaining the updates, or some
training material updated for example.&lt;/p&gt;&lt;p&gt;However, it can change in other ways too. Internal refactorings which change how
things are implemented (for example, to make the code easier to follow), but
don&amp;#x27;t change the experience of the developer using the component or the end user
using it. With these kinds of changes, no additional work outside the component
is needed.&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;The Test User&lt;/h2&gt;&lt;p&gt;So what does this have to do with testing? One thing that I talk about a lot is
&amp;quot;&lt;a href="https://twitter.com/kentcdodds/status/977018512689455106"&gt;The more your tests resemble the way your software is used, the more confidence they can give you.&lt;/a&gt; &amp;quot;
So knowing how your software is used is really valuable. It gives you a guide
for knowing how to test the component.&lt;/p&gt;&lt;p&gt;But far too often, I see tests which are
&lt;a href="https://kentcdodds.com/blog/testing-implementation-details"&gt;testing implementation details&lt;/a&gt; (read
this before continuing if you haven&amp;#x27;t already). When you do this, you introduce
a third user. The developer user and the end user are really all that matters
for this component. So long as it serves those two, then it has a reason to
exist. And when you&amp;#x27;re maintaining the component you need to keep those two
users in mind to make sure that if you break the contract with them, you do
something to handle that change.&lt;/p&gt;&lt;p&gt;But as soon as you start testing things which your developer user and end user
don&amp;#x27;t know or care about (implementation details), you add a third testing user,
you&amp;#x27;re now having to keep that third user in your head and make sure you account
for changes that affect the testing user as well.&lt;/p&gt;&lt;p&gt;And for what? To get &amp;quot;confidence?&amp;quot; But what are you getting confidence in when
you test things this way? You&amp;#x27;re getting confidence that things work for the
testing user. But nobody cares about the testing user. The testing user doesn&amp;#x27;t
pay the bills like the end user. It doesn&amp;#x27;t affect the rest of the system like
the developer user.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;Writing tests that include implementation details is all downside and no upside.
Focus on the developer user and the end user and your tests will actually give
you confidence that things will continue to work for them. When your tests break
it becomes a cue for you to know that you have other changes to make elsewhere
to account for the changes you&amp;#x27;ve made. Avoid testing implementation details and
you&amp;#x27;ll be much better off.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;P.S. If you&amp;#x27;re interested to know how I&amp;#x27;d test this component in a way that&amp;#x27;s
free of implementation details, then you can
&lt;a href="https://github.com/kentcdodds/advanced-react-patterns/blob/06a16f86d2397c4451da9faf9aeb64cbe4452ff6/src/__tests__/01.js"&gt;look at the tests here&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;P.S.P.S. There are definitely situations where mocking and testing
implementation details is necessary, read more about that in
&lt;a href="https://kentcdodds.com/blog/the-merits-of-mocking"&gt;The Merits of Mocking&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/avoid-the-test-user"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Authentication in React Applications]]></title>
<description><![CDATA[Skipping to the end Here's the secret to this blog post in one short code example: That's it.
Most apps which
require authentication of any kind can be drastically simplified by that one
little trick. Rather than trying to do something fancy to…]]></description>
<link>https://kentcdodds.com/blog/authentication-in-react-applications</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/authentication-in-react-applications</guid>
<pubDate>Mon, 20 May 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;h2&gt;Skipping to the end&lt;/h2&gt;&lt;p&gt;Here&amp;#x27;s the secret to this blog post in one short code example:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;import React from &amp;#x27;react&amp;#x27;
import {useUser} from &amp;#x27;./context/auth&amp;#x27;
import AuthenticatedApp from &amp;#x27;./authenticated-app&amp;#x27;
import UnauthenticatedApp from &amp;#x27;./unauthenticated-app&amp;#x27;
function App() {
const user = useUser()
return user ? &amp;lt;AuthenticatedApp /&amp;gt; : &amp;lt;UnauthenticatedApp /&amp;gt;
}
export App
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That&amp;#x27;s it.
&lt;a href="https://twitter.com/kentcdodds/status/1131184429169168387"&gt;Most apps&lt;/a&gt; which
require authentication of any kind can be drastically simplified by that one
little trick. Rather than trying to do something fancy to redirect the user when
they happen to land on a page that they&amp;#x27;re not supposed to, instead you don&amp;#x27;t
render that stuff at all. Things get even cooler when you do this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;import React from &amp;#x27;react&amp;#x27;
import {useUser} from &amp;#x27;./context/auth&amp;#x27;
const AuthenticatedApp = React.lazy(() =&amp;gt; import(&amp;#x27;./authenticated-app&amp;#x27;))
const UnauthenticatedApp = React.lazy(() =&amp;gt; import(&amp;#x27;./unauthenticated-app&amp;#x27;))
function App() {
const user = useUser()
return user ? &amp;lt;AuthenticatedApp /&amp;gt; : &amp;lt;UnauthenticatedApp /&amp;gt;
}
export App
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Sweet, now you don&amp;#x27;t even bother loading the code until it&amp;#x27;s needed. So the
login screen shows up faster for unauthenticated users and the app loads faster
for authenticated users.&lt;/p&gt;&lt;p&gt;What the &lt;code&gt;&amp;lt;AuthenticatedApp /&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;UnauthenticatedApp /&amp;gt;&lt;/code&gt; do is totally up to
you. Maybe they render unique routers. Maybe they even use some of the same
components. But whatever they do, you don&amp;#x27;t have to bother wondering whether the
user is logged in because you make it literally impossible to render one side of
the app or the other if there is no user.&lt;/p&gt;&lt;h2&gt;How do we get here?&lt;/h2&gt;&lt;blockquote&gt;&lt;p&gt;If you want to just look at how it&amp;#x27;s all done, then you can checkout
&lt;a href="https://github.com/kentcdodds/bookshelf"&gt;the bookshelf repo&lt;/a&gt; which I made for
my &lt;a href="https://kentcdodds.com/workshops/build-react-apps"&gt;Build ReactJS Applications Workshop&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Ok, so what do you do to get to this point? Let&amp;#x27;s start by looking at where
we&amp;#x27;re actually rendering the app:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;import React from &amp;#x27;react&amp;#x27;
import ReactDOM from &amp;#x27;react-dom&amp;#x27;
import App from &amp;#x27;./app&amp;#x27;
import AppProviders from &amp;#x27;./context&amp;#x27;
ReactDOM.render(
&amp;lt;AppProviders&amp;gt;
&amp;lt;App /&amp;gt;
&amp;lt;/AppProviders&amp;gt;,
document.getElementById(&amp;#x27;root&amp;#x27;),
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And here&amp;#x27;s that &lt;code&gt;&amp;lt;AppProviders /&amp;gt;&lt;/code&gt; component:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;import React from &amp;#x27;react&amp;#x27;
import {AuthProvider} from &amp;#x27;./auth-context&amp;#x27;
import {UserProvider} from &amp;#x27;./user-context&amp;#x27;
function AppProviders({children}) {
return (
&amp;lt;AuthProvider&amp;gt;
&amp;lt;UserProvider&amp;gt;{children}&amp;lt;/UserProvider&amp;gt;
&amp;lt;/AuthProvider&amp;gt;
)
}
export default AppProviders
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, cool, so we have a provider from the app&amp;#x27;s authentication and one for the
user&amp;#x27;s data. So presumably the &lt;code&gt;&amp;lt;AuthProvider /&amp;gt;&lt;/code&gt; would be responsible for
bootstrapping the app data (if the user&amp;#x27;s authentication token is already in
localStorage then we can simply retrieve the user&amp;#x27;s data using that token). Then
the &lt;code&gt;&amp;lt;UserProvider /&amp;gt;&lt;/code&gt; would be responsible for keeping the user data up to date
in memory and on the server as we make changes to the user&amp;#x27;s data (like their
email address/bio/etc.).&lt;/p&gt;&lt;p&gt;&lt;a href="https://github.com/kentcdodds/bookshelf/blob/69bde2c117660bd988ffbc60f387165d2f852c62/src/context/auth-context.js"&gt;The &lt;code&gt;auth-context.js&lt;/code&gt; file&lt;/a&gt;
has some stuff in it that&amp;#x27;s outside the scope of this blog post/domain specific,
so I&amp;#x27;m only going to show a slimmed down/modified version of it:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;import React from &amp;#x27;react&amp;#x27;
import {FullPageSpinner} from &amp;#x27;../components/lib&amp;#x27;
const AuthContext = React.createContext()
function AuthProvider(props) {
// code for pre-loading the user&amp;#x27;s information if we have their token in localStorage goes here
// 🚨 this is the important bit.
// Normally your provider components render the context provider with a value.
// But we post-pone rendering any of the children until after we&amp;#x27;ve determined
// whether or not we have a user token and if we do, then we render a spinner
// while we go retrieve that user&amp;#x27;s information.
if (weAreStillWaitingToGetTheUserData) {
return &amp;lt;FullPageSpinner /&amp;gt;
}
const login = () =&amp;gt; {} // make a login request
const register = () =&amp;gt; {} // register the user
const logout = () =&amp;gt; {} // clear the token in localStorage and the user data
// note, I&amp;#x27;m not bothering to optimize this `value` with React.useMemo here
// because this is the top-most component rendered in our app and it will very
// rarely re-render/cause a performance problem.
return (
&amp;lt;AuthContext.Provider value={{data, login, logout, register}} {...props} /&amp;gt;
)
}
const useAuth = () =&amp;gt; React.useContext(AuthContext)
export {AuthProvider, useAuth}
// the UserProvider in user-context.js is basically:
// const UserProvider = props =&amp;gt; (
// &amp;lt;UserContext.Provider value={useAuth().data.user} {...props} /&amp;gt;
// )
// and the useUser hook is basically this:
// const useUser = () =&amp;gt; React.useContext(UserContext)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The key idea that drastically simplifies authentication in your app is this:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;The component which has the user data prevents the rest of the app from being
rendered until the user data is retrieved or it&amp;#x27;s determined that there is no
logged-in user&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;It does this by simply returning a spinner instead of rendering the rest of the
app. It&amp;#x27;s not rendering a router or anything at all really. Just a spinner until
we know whether we have a user token &lt;em&gt;and&lt;/em&gt; attempt to get that user&amp;#x27;s
information. Once that&amp;#x27;s done, then we can continue with rendering the rest of
the app.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;Many apps are different. If you&amp;#x27;re doing server-side rendering then you probably
don&amp;#x27;t need a spinner and you have the user&amp;#x27;s information available to you by the
time you start rendering. Even in that situation, taking a branch higher up in
the tree of your app drastically simplifies the maintenance of your app.&lt;/p&gt;&lt;p&gt;I hope this is helpful to you. You can checkout
&lt;a href="https://github.com/kentcdodds/bookshelf"&gt;the bookshelf repo&lt;/a&gt;
(&lt;a href="https://codesandbox.io/s/github/kentcdodds/bookshelf"&gt;or even edit it on codesandbox&lt;/a&gt;)
for a more complete picture of what all this is like in a more realistic
scenario with all the pieces together.&lt;/p&gt;&lt;h2&gt;P.S.&lt;/h2&gt;&lt;p&gt;Several people have asked me: What if my app has lots of shared screens between
authenticated and unauthenticated users (like Twitter) rather than having very
different screens between authenticated and unauthenticated users (like Gmail)?&lt;/p&gt;&lt;p&gt;In that case then you&amp;#x27;ll probably need to litter a bunch of &lt;code&gt;useUser()&lt;/code&gt; hooks
all over the codebase. You might make it even easier with a
&lt;code&gt;useIsAuthenticated()&lt;/code&gt; hook that simply returns a boolean if the user is logged
in. Either way, it&amp;#x27;s pretty simple thanks to context + hooks :)&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/authentication-in-react-applications"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[How to optimize your context value]]></title>
<description><![CDATA[NOTE: I want to add that the times it's important to optimize your context
value is when a certain combination of the following conditions are met: Your context value changes frequently Your context has many consumers You are bothering to use React…]]></description>
<link>https://kentcdodds.com/blog/how-to-optimize-your-context-value</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/how-to-optimize-your-context-value</guid>
<pubDate>Mon, 06 May 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;blockquote&gt;&lt;p&gt;NOTE: I want to add that the times it&amp;#x27;s important to optimize your context
value is when a certain combination of the following conditions are met:&lt;/p&gt;&lt;/blockquote&gt;&lt;ol&gt;&lt;li&gt;Your context value changes frequently&lt;/li&gt;&lt;li&gt;Your context has many consumers&lt;/li&gt;&lt;li&gt;You are bothering to use &lt;code&gt;React.memo&lt;/code&gt; (because things are legit slow)&lt;/li&gt;&lt;li&gt;You&amp;#x27;ve actually measured things and you know it&amp;#x27;s slow and needs to be
optimized&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;If that explains your situation, then read on (and don&amp;#x27;t miss the alternative
solution which is honestly probably better anyway). In fact, the alternative is
definitely better and I&amp;#x27;ve reworked the blog post to remove my original
recommendation and just show the alternative. If you want to see my original,
&lt;a href="https://github.com/kentcdodds/kentcdodds.com/blob/319db97260078ea4c263e75166f05e2cea21ccd1/content/blog/how-to-optimize-your-context-value/index.md"&gt;read the original stuff here&lt;/a&gt;.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;No seriously, if you&amp;#x27;re going to do this stuff just because you &lt;em&gt;think&lt;/em&gt; your
code &lt;em&gt;might&lt;/em&gt; be slow, then don&amp;#x27;t bother. I&amp;#x27;m not joking. React is really fast
and adding complexity in the name of performance when performance is good
enough is just wasteful of your &amp;quot;complexity budget&amp;quot;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;The simplest solution to optimizing your context value involves using
&lt;code&gt;useReducer&lt;/code&gt; for your state management and putting the &lt;code&gt;state&lt;/code&gt; in one context
provider and the &lt;code&gt;dispatch&lt;/code&gt; in another. Here&amp;#x27;s that:&lt;/p&gt;&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/ynn88nx9x?view=editor" style="width:100%;height:500px;border-width:0px;border-radius:4px;overflow:hidden"&gt;&lt;/iframe&gt;&lt;/p&gt;&lt;p&gt;Not only do you not need to &lt;code&gt;useMemo&lt;/code&gt; in this case, but you actually can avoid
re-rendering the components that just use the updater context:&lt;/p&gt;&lt;p&gt;&lt;img src="https://kentcdodds.com/split-contexts-4c34ec3ca8069d6d9bea6abc52759a35.gif" alt="clicking &amp;quot;force render&amp;quot; three times and &amp;quot;Increment count&amp;quot; twice"/&gt;&lt;/p&gt;&lt;p&gt;This is the same as with my original &lt;code&gt;useMemo&lt;/code&gt; solution, except because the
&lt;code&gt;&amp;lt;Counter /&amp;gt;&lt;/code&gt; component&amp;#x27;s context isn&amp;#x27;t getting updated, we avoid the re-render
of that component entirely which is cool.&lt;/p&gt;&lt;p&gt;I personally feel like this is more complicated of an API than is necessary for
most situations, so I wouldn&amp;#x27;t bother optimizing most of my contexts. But if you
really have all the problems mentioned above, then consider doing this as a
simple way to side-step the issue.&lt;/p&gt;&lt;p&gt;Also, don&amp;#x27;t miss
&lt;a href="https://kentcdodds.com/blog/how-to-use-react-context-effectively"&gt;How to use React Context effectively&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/how-to-optimize-your-context-value"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[How to use React Context effectively]]></title>
<description><![CDATA[In
Application State Management with React ,
I talk about how using a mix of local state and React Context can help you
manage state well in any React application. I showed some examples and I want to
call out a few things about those examples and…]]></description>
<link>https://kentcdodds.com/blog/how-to-use-react-context-effectively</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/how-to-use-react-context-effectively</guid>
<pubDate>Mon, 29 Apr 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;In
&lt;a href="https://kentcdodds.com/blog/application-state-management-with-react"&gt;Application State Management with React&lt;/a&gt;,
I talk about how using a mix of local state and React Context can help you
manage state well in any React application. I showed some examples and I want to
call out a few things about those examples and how you can create React context
consumers effectively so you avoid some problems and improve the developer
experience and maintainability of the context objects you create for your
application and/or libraries.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Note, please do read
&lt;a href="https://kentcdodds.com/blog/application-state-management-with-react"&gt;Application State Management with React&lt;/a&gt;
and follow the advice that you shouldn&amp;#x27;t be reaching for context to solve
every state sharing problem that crosses your desk. But when you do need to
reach for context, hopefully this blog post will help you know how to do so
effectively. Also, remember that context does NOT have to be global to the
whole app, but can be applied to one part of your tree and you can (and
probably should) have multiple logically separated contexts in your app.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;First, let&amp;#x27;s create a file at &lt;code&gt;src/count-context.js&lt;/code&gt; and we&amp;#x27;ll create our
context there:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;// src/count-context.js
import React from &amp;#x27;react&amp;#x27;
const CountStateContext = React.createContext()
const CountDispatchContext = React.createContext()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;First off, I don&amp;#x27;t have an initial value for the &lt;code&gt;CountStateContext&lt;/code&gt;. If I
wanted an initial value, I would call &lt;code&gt;React.createContext({count: 0})&lt;/code&gt;. But I
don&amp;#x27;t include a default value and that&amp;#x27;s intentional. The &lt;code&gt;defaultValue&lt;/code&gt; is only
useful in a situation like this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx" metastring="{2}"&gt;function CountDisplay() {
const {count} = React.useContext(CountStateContext)
return &amp;lt;div&amp;gt;{count}&amp;lt;/div&amp;gt;
}
ReactDOM.render(&amp;lt;CountDisplay /&amp;gt;, document.getElementById(&amp;#x27;⚛️&amp;#x27;))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Because we don&amp;#x27;t have a default value for our &lt;code&gt;CountStateContext&lt;/code&gt;, we&amp;#x27;ll get an
error on the highlighted line where we&amp;#x27;re destructing the return value of
&lt;code&gt;useContext&lt;/code&gt;. This is because our default value is &lt;code&gt;undefined&lt;/code&gt; and you cannot
destructure &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;None of us likes runtime errors, so your knee-jerk reaction may be to add a
default value to avoid the runtime error. However, what use would the context be
if it didn&amp;#x27;t have an actual value? If it&amp;#x27;s just using the default value that&amp;#x27;s
been provided, then it can&amp;#x27;t really do much good. 99% of the time that you&amp;#x27;re
going to be creating and using context in your application, you want your
context consumers (those using &lt;code&gt;useContext&lt;/code&gt;) to be rendered within a provider
which can provide a useful value.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Note, there are situations where default values are useful, but most of the
time they&amp;#x27;re not necessary or useful.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;a href="https://reactjs.org/docs/context.html#reactcreatecontext"&gt;The React docs&lt;/a&gt;
suggest that providing a default value &amp;quot;can be helpful in testing components in
isolation without wrapping them.&amp;quot; While it&amp;#x27;s true that it allows you to do this,
I disagree that it&amp;#x27;s better than wrapping your components with the necessary
context. Remember that every time you do something in your test that you don&amp;#x27;t
do in your application, you reduce the amount of confidence that test can give
you. &lt;a href="https://kentcdodds.com/blog/the-merits-of-mocking"&gt;There are reasons to do this&lt;/a&gt;, but that&amp;#x27;s not
one of them.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Note: If you&amp;#x27;re using Flow or TypeScript, not providing a default value can be
really annoying for people who are using &lt;code&gt;React.useContext&lt;/code&gt;, but I&amp;#x27;ll show you
how to avoid that problem altogether below. Keep reading!&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;strong&gt;What&amp;#x27;s this &lt;code&gt;CountDispatchContext&lt;/code&gt; thing all about?&lt;/strong&gt; I&amp;#x27;ve been playing around
with context for a while, and talking with friends at Facebook who have been
playing around with it for longer and I can tell you that the simplest way to
avoid problems with context (especially when you start calling &lt;code&gt;dispatch&lt;/code&gt; in
effects) is to split up the state and dispatch in context. Stay with me here!&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;If you want to dive into this a bit more, then read
&lt;a href="https://kentcdodds.com/blog/how-to-optimize-your-context-value"&gt;How to optimize your context value&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;h2&gt;The Custom Provider Component&lt;/h2&gt;&lt;p&gt;Ok, let&amp;#x27;s continue. For this context module to be useful &lt;em&gt;at all&lt;/em&gt; we need to use
the Provider and expose a component that provides a value. Our component will be
used like this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx" metastring="{3,6}"&gt;function App() {
return (
&amp;lt;CountProvider&amp;gt;
&amp;lt;CountDisplay /&amp;gt;
&amp;lt;Counter /&amp;gt;
&amp;lt;/CountProvider&amp;gt;
)
}
ReactDOM.render(&amp;lt;App /&amp;gt;, document.getElementById(&amp;#x27;⚛️&amp;#x27;))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So let&amp;#x27;s make a component that can be used like that:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;// src/count-context.js
import React from &amp;#x27;react&amp;#x27;
const CountStateContext = React.createContext()
const CountDispatchContext = React.createContext()
function countReducer(state, action) {
switch (action.type) {
case &amp;#x27;increment&amp;#x27;: {
return {count: state.count + 1}
}
case &amp;#x27;decrement&amp;#x27;: {
return {count: state.count - 1}
}
default: {
throw new Error(`Unhandled action type: ${action.type}`)
}
}
}
function CountProvider({children}) {
const [state, dispatch] = React.useReducer(countReducer, {count: 0})
return (
&amp;lt;CountStateContext.Provider value={state}&amp;gt;
&amp;lt;CountDispatchContext.Provider value={dispatch}&amp;gt;
{children}
&amp;lt;/CountDispatchContext.Provider&amp;gt;
&amp;lt;/CountStateContext.Provider&amp;gt;
)
}
export {CountProvider}
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;NOTE: this is a contrived example that I&amp;#x27;m intentionally over-engineering to
show you what a more real-world scenario would be like. &lt;strong&gt;This does not mean
it has to be this complicated every time!&lt;/strong&gt; Feel free to use &lt;code&gt;useState&lt;/code&gt; if
that suites your scenario. In addition, some providers are going to be short
and simple like this, and others are going to be MUCH more involved with many
hooks.&lt;/p&gt;&lt;/blockquote&gt;&lt;h2&gt;The Custom Consumer Hook&lt;/h2&gt;&lt;p&gt;Most of the APIs for context usages I&amp;#x27;ve seen in the wild look something like
this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;import React from &amp;#x27;react&amp;#x27;
import {SomethingContext} from &amp;#x27;some-context-package&amp;#x27;
function YourComponent() {
const something = React.useContext(SomethingContext)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But I think that&amp;#x27;s a missed opportunity at providing a better user experience.
Instead, I think it should be like this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;import React from &amp;#x27;react&amp;#x27;
import {useSomething} from &amp;#x27;some-context-package&amp;#x27;
function YourComponent() {
const something = useSomething()
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This has the benefit of you being able to do a few things which I&amp;#x27;ll show you in
the implementation now:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx" metastring="{32-38,40-46,48}"&gt;// src/count-context.js
import React from &amp;#x27;react&amp;#x27;
const CountStateContext = React.createContext()
const CountDispatchContext = React.createContext()
function countReducer(state, action) {
switch (action.type) {
case &amp;#x27;increment&amp;#x27;: {
return {count: state.count + 1}
}
case &amp;#x27;decrement&amp;#x27;: {
return {count: state.count - 1}
}
default: {
throw new Error(`Unhandled action type: ${action.type}`)
}
}
}
function CountProvider({children}) {
const [state, dispatch] = React.useReducer(countReducer, {count: 0})
return (
&amp;lt;CountStateContext.Provider value={state}&amp;gt;
&amp;lt;CountDispatchContext.Provider value={dispatch}&amp;gt;
{children}
&amp;lt;/CountDispatchContext.Provider&amp;gt;
&amp;lt;/CountStateContext.Provider&amp;gt;
)
}
function useCountState() {
const context = React.useContext(CountStateContext)
if (context === undefined) {
throw new Error(&amp;#x27;useCountState must be used within a CountProvider&amp;#x27;)
}
return context
}
function useCountDispatch() {
const context = React.useContext(CountDispatchContext)
if (context === undefined) {
throw new Error(&amp;#x27;useCountDispatch must be used within a CountProvider&amp;#x27;)
}
return context
}
export {CountProvider, useCountState, useCountDispatch}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;First, the &lt;code&gt;useCountState&lt;/code&gt; and &lt;code&gt;useCountDispatch&lt;/code&gt; custom hooks use
&lt;code&gt;React.useContext&lt;/code&gt; to get the provided context value from the nearest
&lt;code&gt;CountProvider&lt;/code&gt;. However, if there is no value, then we throw a helpful error
message indicating that the hook is not being called within a function component
that is rendered within a &lt;code&gt;CountProvider&lt;/code&gt;. This is most certainly a mistake, so
providing the error message is valuable. &lt;em&gt;&lt;strong&gt;#FailFast&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;&lt;h2&gt;The Custom Consumer Component&lt;/h2&gt;&lt;p&gt;If you&amp;#x27;re able to use hooks at all, then skip this section. However if you need
to support React &lt;code&gt;&amp;lt;&lt;/code&gt; 16.8.0, or you think the Context needs to be consumed by
class components, then here&amp;#x27;s how you could do something similar with the
render-prop based API for context consumers:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;function CountConsumer({children}) {
return (
&amp;lt;CountContext.Consumer&amp;gt;
{context =&amp;gt; {
if (context === undefined) {
throw new Error(&amp;#x27;CountConsumer must be used within a CountProvider&amp;#x27;)
}
return children(context)
}}
&amp;lt;/CountContext.Consumer&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is what I used to do before we had hooks and it worked well. I would not
recommend bothering with this if you can use hooks though. Hooks are much
better.&lt;/p&gt;&lt;h2&gt;TypeScript / Flow&lt;/h2&gt;&lt;p&gt;I promised I&amp;#x27;d show you how to avoid issues with skipping the &lt;code&gt;defaultValue&lt;/code&gt;
when using TypeScript or Flow. Guess what! By doing what I&amp;#x27;m suggesting, you
avoid the problem by default! It&amp;#x27;s actually not a problem at all. Check it out:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript" metastring="{9-12,40-44,48-52}"&gt;// src/count-context.tsx
import * as React from &amp;#x27;react&amp;#x27;
type Action = {type: &amp;#x27;increment&amp;#x27;} | {type: &amp;#x27;decrement&amp;#x27;}
type Dispatch = (action: Action) =&amp;gt; void
type State = {count: number}
type CountProviderProps = {children: React.ReactNode}
const CountStateContext = React.createContext&amp;lt;State | undefined&amp;gt;(undefined)
const CountDispatchContext = React.createContext&amp;lt;Dispatch | undefined&amp;gt;(
undefined,
)
function countReducer(state: State, action: Action) {
switch (action.type) {
case &amp;#x27;increment&amp;#x27;: {
return {count: state.count + 1}
}
case &amp;#x27;decrement&amp;#x27;: {
return {count: state.count - 1}
}
default: {
throw new Error(`Unhandled action type: ${action.type}`)
}
}
}
function CountProvider({children}: CountProviderProps) {
const [state, dispatch] = React.useReducer(countReducer, {count: 0})
return (
&amp;lt;CountStateContext.Provider value={state}&amp;gt;
&amp;lt;CountDispatchContext.Provider value={dispatch}&amp;gt;
{children}
&amp;lt;/CountDispatchContext.Provider&amp;gt;
&amp;lt;/CountStateContext.Provider&amp;gt;
)
}
function useCountState() {
const context = React.useContext(CountStateContext)
if (context === undefined) {
throw new Error(&amp;#x27;useCountState must be used within a CountProvider&amp;#x27;)
}
return context
}
function useCountDispatch() {
const context = React.useContext(CountDispatchContext)
if (context === undefined) {
throw new Error(&amp;#x27;useCountDispatch must be used within a CountProvider&amp;#x27;)
}
return context
}
export {CountProvider, useCountState, useCountDispatch}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With that, anyone can use &lt;code&gt;useCountState&lt;/code&gt; or &lt;code&gt;useCountDispatch&lt;/code&gt; without having
to do any undefined-checks, because we&amp;#x27;re doing it for them!&lt;/p&gt;&lt;p&gt;&lt;a href="https://codesandbox.io/s/bitter-night-i5mhj"&gt;Here&amp;#x27;s a working codesandbox&lt;/a&gt;&lt;/p&gt;&lt;h2&gt;What about dispatch &lt;code&gt;type&lt;/code&gt; typos?&lt;/h2&gt;&lt;p&gt;At this point, you reduxers are yelling: &amp;quot;Hey, where are the action creators?!&amp;quot;
If you want to implement action creators that is fine by me, but I never liked
action creators. I have always felt like they were an unnecessary abstraction.
Also, if you are using TypeScript or Flow and have your actions well typed, then
you should not need them. You can get autocomplete and inline type errors!&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1035px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/d99d4329b1d7ebd2e63bf76471f540ab/27aa4/auto-complete.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:25%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="dispatch type getting autocompleted" title="dispatch type getting autocompleted" src="https://kentcdodds.com/static/d99d4329b1d7ebd2e63bf76471f540ab/17fa4/auto-complete.png" srcSet="https://kentcdodds.com/static/d99d4329b1d7ebd2e63bf76471f540ab/f4a45/auto-complete.png 259w,https://kentcdodds.com/static/d99d4329b1d7ebd2e63bf76471f540ab/ef0f6/auto-complete.png 518w,https://kentcdodds.com/static/d99d4329b1d7ebd2e63bf76471f540ab/17fa4/auto-complete.png 1035w,https://kentcdodds.com/static/d99d4329b1d7ebd2e63bf76471f540ab/d6f0c/auto-complete.png 1553w,https://kentcdodds.com/static/d99d4329b1d7ebd2e63bf76471f540ab/27aa4/auto-complete.png 1680w" sizes="(max-width: 1035px) 100vw, 1035px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1035px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/0d45ecb53470729181863636bdafc2b9/05bc5/type-error.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:22.55813953488372%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="type error on a misspelled dispatch type" title="type error on a misspelled dispatch type" src="https://kentcdodds.com/static/0d45ecb53470729181863636bdafc2b9/17fa4/type-error.png" srcSet="https://kentcdodds.com/static/0d45ecb53470729181863636bdafc2b9/f4a45/type-error.png 259w,https://kentcdodds.com/static/0d45ecb53470729181863636bdafc2b9/ef0f6/type-error.png 518w,https://kentcdodds.com/static/0d45ecb53470729181863636bdafc2b9/17fa4/type-error.png 1035w,https://kentcdodds.com/static/0d45ecb53470729181863636bdafc2b9/d6f0c/type-error.png 1553w,https://kentcdodds.com/static/0d45ecb53470729181863636bdafc2b9/05bc5/type-error.png 1720w" sizes="(max-width: 1035px) 100vw, 1035px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;I really like passing &lt;code&gt;dispatch&lt;/code&gt; this way and as a side benefit, &lt;code&gt;dispatch&lt;/code&gt; is
stable for the lifetime of the component that created it, so you don&amp;#x27;t need to
worry about passing it to &lt;code&gt;useEffect&lt;/code&gt; dependencies lists (it makes no difference
whether it is included or not).&lt;/p&gt;&lt;p&gt;If you are not typing your JavaScript (you probably should consider it if you
have not), then the error we throw for missed action types is a failsafe. Also,
read on to the next section because this can help you too.&lt;/p&gt;&lt;h2&gt;What about async actions?&lt;/h2&gt;&lt;p&gt;This is a great question. What happens if you have a situation where you need to
make some asynchronous request and you need to dispatch multiple things over the
course of that request? Sure you could do it at the calling component, but
manually wiring all of that together for every component that needs to do
something like that would be pretty annoying.&lt;/p&gt;&lt;p&gt;What I suggest is you make a helper function within your context module which
accepts &lt;code&gt;dispatch&lt;/code&gt; along with any other data you need, and make that helper be
responsible for dealing with all of that. Here&amp;#x27;s an example from
&lt;a href="https://kentcdodds.com/workshops/advanced-react-patterns"&gt;my Advanced React Patterns workshop&lt;/a&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;// user-context.js
async function updateUser(dispatch, user, updates) {
dispatch({type: &amp;#x27;start update&amp;#x27;, updates})
try {
const updatedUser = await userClient.updateUser(user, updates)
dispatch({type: &amp;#x27;finish update&amp;#x27;, updatedUser})
} catch (error) {
dispatch({type: &amp;#x27;fail update&amp;#x27;, error})
}
}
export {UserProvider, useUserDispatch, useUserState, updateUser}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then you can use that like this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;// user-profile.js
import {useUserState, useUserDispatch, updateUser} from &amp;#x27;./user-context&amp;#x27;
function UserSettings() {
const {user, status, error} = useUserState()
const userDispatch = useUserDispatch()
function handleSubmit(event) {
event.preventDefault()
updateUser(userDispatch, user, formState)
}
// more code...
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I&amp;#x27;m really happy with this pattern and if you&amp;#x27;d like me to teach this at your
company &lt;a href="https://kentcdodds.com/contact"&gt;let me know&lt;/a&gt; (or
&lt;a href="https://kentcdodds.com/workshops/advanced-react-patterns"&gt;add yourself to the waitlist&lt;/a&gt; for the next
time I host the workshop)!&lt;/p&gt;&lt;h2&gt;The state and dispatch separation is annoying&lt;/h2&gt;&lt;p&gt;Some people find this annoying/overly verbose:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const state = useCountState()
const dispatch = useCountDispatch()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;They say &amp;quot;can&amp;#x27;t we just do this?&amp;quot;:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const [state, dispatch] = useCount()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Sure you can:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;function useCount() {
return [useCountState(), useCountDispatch()]
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;So here&amp;#x27;s the final version of the code:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;// src/count-context.js
import React from &amp;#x27;react&amp;#x27;
const CountStateContext = React.createContext()
const CountDispatchContext = React.createContext()
function countReducer(state, action) {
switch (action.type) {
case &amp;#x27;increment&amp;#x27;: {
return {count: state.count + 1}
}
case &amp;#x27;decrement&amp;#x27;: {
return {count: state.count - 1}
}
default: {
throw new Error(`Unhandled action type: ${action.type}`)
}
}
}
function CountProvider({children}) {
const [state, dispatch] = React.useReducer(countReducer, {count: 0})
return (
&amp;lt;CountStateContext.Provider value={state}&amp;gt;
&amp;lt;CountDispatchContext.Provider value={dispatch}&amp;gt;
{children}
&amp;lt;/CountDispatchContext.Provider&amp;gt;
&amp;lt;/CountStateContext.Provider&amp;gt;
)
}
function useCountState() {
const context = React.useContext(CountStateContext)
if (context === undefined) {
throw new Error(&amp;#x27;useCountState must be used within a CountProvider&amp;#x27;)
}
return context
}
function useCountDispatch() {
const context = React.useContext(CountDispatchContext)
if (context === undefined) {
throw new Error(&amp;#x27;useCountDispatch must be used within a CountProvider&amp;#x27;)
}
return context
}
export {CountProvider, useCountState, useCountDispatch}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href="https://codesandbox.io/s/react-codesandbox-je6cc"&gt;Here&amp;#x27;s a working codesandbox&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Note that I&amp;#x27;m &lt;em&gt;NOT&lt;/em&gt; exporting &lt;code&gt;CountContext&lt;/code&gt;. This is intentional. I expose only
one way to provide the context value and only one way to consume it. This allows
me to ensure that people are using the context value the way it should be and it
allows me to provide useful utilities for my consumers.&lt;/p&gt;&lt;p&gt;I hope this is useful to you! Remember:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;You shouldn&amp;#x27;t be reaching for context to solve every state sharing problem
that crosses your desk.&lt;/li&gt;&lt;li&gt;Context does NOT have to be global to the whole app, but can be applied to
one part of your tree&lt;/li&gt;&lt;li&gt;You can (and probably should) have multiple logically separated contexts in
your app.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Good luck!&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/how-to-use-react-context-effectively"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Application State Management with React]]></title>
<description><![CDATA[Managing state is arguably the hardest part of any application. It's why there
are so many state management libraries available and more coming around every
day (and even some built on top of others... There are hundreds of "easier
redux…]]></description>
<link>https://kentcdodds.com/blog/application-state-management-with-react</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/application-state-management-with-react</guid>
<pubDate>Mon, 22 Apr 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;Managing state is arguably the hardest part of any application. It&amp;#x27;s why there
are so many state management libraries available and more coming around every
day (and even some built on top of others... There are hundreds of &amp;quot;easier
redux&amp;quot; abstractions on npm). Despite the fact that state management is a hard
problem, I would suggest that one of the things that makes it so difficult is
that we often over-engineer our solution to the problem.&lt;/p&gt;&lt;p&gt;There&amp;#x27;s one state management solution that I&amp;#x27;ve personally tried to implement
for as long as I&amp;#x27;ve been using React, and with the release of React hooks (and
massive improvements to React context) this method of state management has been
drastically simplified.&lt;/p&gt;&lt;p&gt;We often talk about React components as lego building blocks to build our
applications, and I think that when people hear this, they somehow think this
excludes the state aspect. The &amp;quot;secret&amp;quot; behind my personal solution to the state
management problem is to think of how your application&amp;#x27;s state maps to the
application&amp;#x27;s tree structure.&lt;/p&gt;&lt;p&gt;One of the reasons redux was so successful was the fact that react-redux solved
the &lt;a href="https://kentcdodds.com/blog/prop-drilling"&gt;prop drilling&lt;/a&gt; problem. The fact that you could share
data across different parts of your tree by simply passing your component into
some magical &lt;code&gt;connect&lt;/code&gt; function was wonderful. Its use of reducers/action
creators/etc. is great too, but I&amp;#x27;m convinced that the ubiquity of redux is
because it solved the prop drilling pain point for developers.&lt;/p&gt;&lt;p&gt;Unfortunately, this led to the reason that I only ever used redux on one
project: I consistently see developers putting &lt;em&gt;all&lt;/em&gt; of their state into redux.
Not just global application state, but local state as well. This leads to a lot
of problems, not the least of which is that when you&amp;#x27;re maintaining any state
interaction, it involves interacting with reducers, action creators/types, and
dispatch calls, which ultimately results in having to open many files and trace
through the code in your head to figure out what&amp;#x27;s happening and what impact it
has on the rest of the codebase.&lt;/p&gt;&lt;p&gt;To be clear, this is fine for state that is truly global, but for simple state
(like whether a modal is open or form input value state) this is a big problem.
To make matters worse, it doesn&amp;#x27;t scale very well. The larger your application
gets, the harder this problem becomes. Sure you can hook up different reducers
to manage different parts of your application, but the indirection of going
through all these action creators and reducers is not optimal.&lt;/p&gt;&lt;p&gt;Having all your application state in a single object can also lead to other
problems, even if you&amp;#x27;re not using Redux. When a React &lt;code&gt;&amp;lt;Context.Provider&amp;gt;&lt;/code&gt; gets
a new value, all the components that consume that value are updated and have to
render, even if it&amp;#x27;s a function component that only cares about part of the
data. That might lead to potential performance issues. (React-Redux v6 also
tried to use this approach until they realized it wouldn&amp;#x27;t work right with
hooks, which forced them to use a different approach with v7 to solve these
issues.) But my point is that you don&amp;#x27;t have this problem if you have your state
more logically separated and located in the react tree closer to where it
matters.&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;Here&amp;#x27;s the real kicker, if you&amp;#x27;re building an application with React, you
already have a state management library installed in your application. You don&amp;#x27;t
even need to &lt;code&gt;npm install&lt;/code&gt; (or &lt;code&gt;yarn add&lt;/code&gt;) it. It costs no extra bytes for your
users, it integrates with all React packages on npm, and it&amp;#x27;s already well
documented by the React team. It&amp;#x27;s React itself.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;React is a state management library&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;When you build a React application, you&amp;#x27;re assembling a bunch of components to
make a tree of components starting at your &lt;code&gt;&amp;lt;App /&amp;gt;&lt;/code&gt; and ending at your
&lt;code&gt;&amp;lt;input /&amp;gt;&lt;/code&gt;s, &lt;code&gt;&amp;lt;div /&amp;gt;&lt;/code&gt;s and &lt;code&gt;&amp;lt;button /&amp;gt;&lt;/code&gt;s. You don&amp;#x27;t manage all of the
low-level composite components that your application renders in one central
location. Instead, you let each individual component manage that and it ends up
being a really effective way to build your UI. You can do this with your state
as well, and it&amp;#x27;s very likely that you do today:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript" metastring="{2}"&gt;function Counter() {
const [count, setCount] = React.useState(0)
const increment = () =&amp;gt; setCount(c =&amp;gt; c + 1)
return &amp;lt;button onClick={increment}&amp;gt;{count}&amp;lt;/button&amp;gt;
}
function App() {
return &amp;lt;Counter /&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href="https://codesandbox.io/s/4qzj73lozx?fontsize=14&amp;amp;hidenavigation=1&amp;amp;module=%2Fsrc%2F01-simple-count.js&amp;amp;moduleview=1"&gt;&lt;img src="https://codesandbox.io/static/img/play-codesandbox.svg" alt="Edit React Codesandbox"/&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Note that everything I&amp;#x27;m talking about here works with class components as well.
Hooks just make things a bit easier (especially context which we&amp;#x27;ll get into in
a minute).&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript" metastring="{2}"&gt;class Counter extends React.Component {
state = {count: 0}
increment = () =&amp;gt; this.setState(({count}) =&amp;gt; ({count: count + 1}))
render() {
return &amp;lt;button onClick={this.increment}&amp;gt;{this.state.count}&amp;lt;/button&amp;gt;
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;quot;Ok, Kent, sure having a single element of state managed in a single component
is easy, but what do you do when I need to share that state across components?
For example, what if I wanted to do this:&amp;quot;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript" metastring="{3}"&gt;function CountDisplay() {
// where does `count` come from?
return &amp;lt;div&amp;gt;The current counter count is {count}&amp;lt;/div&amp;gt;
}
function App() {
return (
&amp;lt;div&amp;gt;
&amp;lt;CountDisplay /&amp;gt;
&amp;lt;Counter /&amp;gt;
&amp;lt;/div&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;quot;The &lt;code&gt;count&lt;/code&gt; is managed inside &lt;code&gt;&amp;lt;Counter /&amp;gt;&lt;/code&gt;, now I need a state management
library to access that &lt;code&gt;count&lt;/code&gt; value from the &lt;code&gt;&amp;lt;CountDisplay /&amp;gt;&lt;/code&gt; and update it
in &lt;code&gt;&amp;lt;Counter /&amp;gt;&lt;/code&gt;!&amp;quot;&lt;/p&gt;&lt;p&gt;The answer to this problem is as old as React itself (older?) and has been in
the docs for as long as I can remember:
&lt;a href="https://reactjs.org/docs/lifting-state-up.html"&gt;Lifting State Up&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;quot;Lifting State Up&amp;quot; is legitimately the answer to the state management problem in
React and it&amp;#x27;s a rock solid one. Here&amp;#x27;s how you apply it to this situation:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;function Counter({count, onIncrementClick}) {
return &amp;lt;button onClick={onIncrementClick}&amp;gt;{count}&amp;lt;/button&amp;gt;
}
function CountDisplay({count}) {
return &amp;lt;div&amp;gt;The current counter count is {count}&amp;lt;/div&amp;gt;
}
function App() {
const [count, setCount] = React.useState(0)
const increment = () =&amp;gt; setCount(c =&amp;gt; c + 1)
return (
&amp;lt;div&amp;gt;
&amp;lt;CountDisplay count={count} /&amp;gt;
&amp;lt;Counter count={count} onIncrementClick={increment} /&amp;gt;
&amp;lt;/div&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href="https://codesandbox.io/s/4qzj73lozx?fontsize=14&amp;amp;hidenavigation=1&amp;amp;module=%2Fsrc%2F02-lift-state.js&amp;amp;moduleview=1"&gt;&lt;img src="https://codesandbox.io/static/img/play-codesandbox.svg" alt="Edit React Codesandbox"/&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;We&amp;#x27;ve just changed who&amp;#x27;s responsible for our state and it&amp;#x27;s really
straightforward. And we could keep lifting state all the way to the top of our
app.&lt;/p&gt;&lt;p&gt;&amp;quot;Sure Kent, ok, but what about the &lt;a href="https://kentcdodds.com/blog/prop-drilling"&gt;prop drilling&lt;/a&gt;
problem?&amp;quot;&lt;/p&gt;&lt;p&gt;This is one problem that&amp;#x27;s actually also had a &amp;quot;solution&amp;quot; for a long time, but
only recently was that solution &amp;quot;official&amp;quot; and &amp;quot;blessed.&amp;quot; As I said, many people
reached for &lt;code&gt;react-redux&lt;/code&gt; because it solved this problem using the mechanism I&amp;#x27;m
referring to without them having to be worried about the warning that was in the
React docs. But now that &lt;code&gt;context&lt;/code&gt; is an officially supported part of the React
API, we can use this directly without any problem:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;// src/count/count-context.js
import React from &amp;#x27;react&amp;#x27;
const CountContext = React.createContext()
function useCount() {
const context = React.useContext(CountContext)
if (!context) {
throw new Error(`useCount must be used within a CountProvider`)
}
return context
}
function CountProvider(props) {
const [count, setCount] = React.useState(0)
const value = React.useMemo(() =&amp;gt; [count, setCount], [count])
return &amp;lt;CountContext.Provider value={value} {...props} /&amp;gt;
}
export {CountProvider, useCount}
// src/count/page.js
import React from &amp;#x27;react&amp;#x27;
import {CountProvider, useCount} from &amp;#x27;./count-context&amp;#x27;
function Counter() {
const [count, setCount] = useCount()
const increment = () =&amp;gt; setCount(c =&amp;gt; c + 1)
return &amp;lt;button onClick={increment}&amp;gt;{count}&amp;lt;/button&amp;gt;
}
function CountDisplay() {
const [count] = useCount()
return &amp;lt;div&amp;gt;The current counter count is {count}&amp;lt;/div&amp;gt;
}
function CountPage() {
return (
&amp;lt;div&amp;gt;
&amp;lt;CountProvider&amp;gt;
&amp;lt;CountDisplay /&amp;gt;
&amp;lt;Counter /&amp;gt;
&amp;lt;/CountProvider&amp;gt;
&amp;lt;/div&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href="https://codesandbox.io/s/4qzj73lozx?fontsize=14&amp;amp;hidenavigation=1&amp;amp;module=%2Fsrc%2F03-context.js&amp;amp;moduleview=1"&gt;&lt;img src="https://codesandbox.io/static/img/play-codesandbox.svg" alt="Edit React Codesandbox"/&gt;&lt;/a&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;NOTE: That particular code example is VERY contrived and I would NOT recommend
you reach for context to solve this specific scenario. Please read
&lt;a href="https://kentcdodds.com/blog/prop-drilling"&gt;Prop Drilling&lt;/a&gt; to get a better sense for why prop
drilling isn&amp;#x27;t necessarily a problem and is often desirable. Don&amp;#x27;t reach for
context too soon!&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;And what&amp;#x27;s cool about this approach is that we could put all the logic for
common ways to update the state in our &lt;code&gt;useContext&lt;/code&gt; hook (or directly in context
if you want I guess):&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;function useCount() {
const context = React.useContext(CountContext)
if (!context) {
throw new Error(`useCount must be used within a CountProvider`)
}
const [count, setCount] = context
const increment = () =&amp;gt; setCount(c =&amp;gt; c + 1)
return {
count,
setCount,
increment,
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href="https://codesandbox.io/s/4qzj73lozx?fontsize=14&amp;amp;hidenavigation=1&amp;amp;module=%2Fsrc%2F04-context-with-logic.js&amp;amp;moduleview=1"&gt;&lt;img src="https://codesandbox.io/static/img/play-codesandbox.svg" alt="Edit React Codesandbox"/&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;And you could easily change this to &lt;code&gt;useReducer&lt;/code&gt; rather than &lt;code&gt;useState&lt;/code&gt; as well:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;function countReducer(state, action) {
switch (action.type) {
case &amp;#x27;INCREMENT&amp;#x27;: {
return {count: state.count + 1}
}
default: {
throw new Error(`Unsupported action type: ${action.type}`)
}
}
}
function CountProvider(props) {
const [state, dispatch] = React.useReducer(countReducer, {count: 0})
const value = React.useMemo(() =&amp;gt; [state, dispatch], [state])
return &amp;lt;CountContext.Provider value={value} {...props} /&amp;gt;
}
function useCount() {
const context = React.useContext(CountContext)
if (!context) {
throw new Error(`useCount must be used within a CountProvider`)
}
const [state, dispatch] = context
const increment = () =&amp;gt; dispatch({type: &amp;#x27;INCREMENT&amp;#x27;})
return {
state,
dispatch,
increment,
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href="https://codesandbox.io/s/4qzj73lozx?fontsize=14&amp;amp;hidenavigation=1&amp;amp;module=%2Fsrc%2F05-context-with-reducer.js&amp;amp;moduleview=1"&gt;&lt;img src="https://codesandbox.io/static/img/play-codesandbox.svg" alt="Edit React Codesandbox"/&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;This gives you an immense amount of flexibility and reduces complexity by orders
of magnitude. Here are a few important things to remember when doing things this
way:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Not everything in your application needs to be in a single state object. Keep
things logically separated (user settings does not necessarily have to be in
the same context as notifications). You will have multiple providers with
this approach.&lt;/li&gt;&lt;li&gt;Not all of your context needs to be globally accessible! &lt;strong&gt;Keep state as
close to where it&amp;#x27;s needed as possible.&lt;/strong&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;More on that second point. Your app tree could look something like this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;function App() {
return (
&amp;lt;ThemeProvider&amp;gt;
&amp;lt;AuthenticationProvider&amp;gt;
&amp;lt;Router&amp;gt;
&amp;lt;Home path=&amp;quot;/&amp;quot; /&amp;gt;
&amp;lt;About path=&amp;quot;/about&amp;quot; /&amp;gt;
&amp;lt;UserPage path=&amp;quot;/:userId&amp;quot; /&amp;gt;
&amp;lt;UserSettings path=&amp;quot;/settings&amp;quot; /&amp;gt;
&amp;lt;Notifications path=&amp;quot;/notifications&amp;quot; /&amp;gt;
&amp;lt;/Router&amp;gt;
&amp;lt;/AuthenticationProvider&amp;gt;
&amp;lt;/ThemeProvider&amp;gt;
)
}
function Notifications() {
return (
&amp;lt;NotificationsProvider&amp;gt;
&amp;lt;NotificationsTab /&amp;gt;
&amp;lt;NotificationsTypeList /&amp;gt;
&amp;lt;NotificationsList /&amp;gt;
&amp;lt;/NotificationsProvider&amp;gt;
)
}
function UserPage({username}) {
return (
&amp;lt;UserProvider username={username}&amp;gt;
&amp;lt;UserInfo /&amp;gt;
&amp;lt;UserNav /&amp;gt;
&amp;lt;UserActivity /&amp;gt;
&amp;lt;/UserProvider&amp;gt;
)
}
function UserSettings() {
// this would be the associated hook for the AuthenticationProvider
const {user} = useAuthenticatedUser()
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Notice that each page can have its own provider that has data necessary for the
components underneath it. Code splitting &amp;quot;just works&amp;quot; for this stuff as well.
How you get data &lt;em&gt;into&lt;/em&gt; each provider is up to the hooks those providers use and
how you retrieve data in your application, but you know just where to start
looking to find out how that works (in the provider).&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;Again, this is something that you can do with class components (you don&amp;#x27;t have
to use hooks). Hooks make this much easier, but you could implement this
philosophy with React 15 no problem. Keep state as local as possible and use
context only when prop drilling really becomes a problem. Doing things this way
will make it easier for you to maintain state interactions.&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/application-state-management-with-react"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[How to know what to test]]></title>
<description><![CDATA[Knowing how to test is great and important. I've created a LOT of content that
teaches people the fundamentals of testing, how to configure tools, how to write
tests for specific scenarios, and so on. But knowing how to write tests is
only half the…]]></description>
<link>https://kentcdodds.com/blog/how-to-know-what-to-test</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/how-to-know-what-to-test</guid>
<pubDate>Sat, 13 Apr 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;Knowing how to test is great and important. I&amp;#x27;ve created a LOT of content that
teaches people the fundamentals of testing, how to configure tools, how to write
tests for specific scenarios, and so on. But knowing &lt;em&gt;how&lt;/em&gt; to write tests is
only half the battle to achieve confidence in your application. Knowing &lt;em&gt;what&lt;/em&gt;
to test is the other–very important–battle.&lt;/p&gt;&lt;p&gt;In my &lt;a href="https://kentcdodds.com/workshops"&gt;workshop material&lt;/a&gt; and on
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;, I do talk about how to
know what to test, but I get asked about this enough that I thought it would be
good to write a blog post about it. So here you go!&lt;/p&gt;&lt;h2&gt;Remembering why we test&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;We write tests to be confident that our application will work when the user
uses them.&lt;/strong&gt; Some people write tests to enhance their workflow as well and
that&amp;#x27;s great, but I&amp;#x27;m ultimately interested in confidence. That being the case,
what we test should map directly to enhancing our confidence. Here&amp;#x27;s the key
point I want you to consider when writing tests:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Think less about the code you are testing and more about the use cases that
code supports.&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;When you think about the code itself, it&amp;#x27;s too easy and natural to start testing
implementation details
(&lt;a href="https://kentcdodds.com/blog/testing-implementation-details"&gt;which is road to disaster&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;Thinking about use cases though gets us closer to writing tests the way the user
uses the application:&lt;/p&gt;&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;The more your tests resemble the way your software is used, the more confidence they can give you.&lt;/p&gt;— Kent C. Dodds (@kentcdodds) &lt;a href="https://twitter.com/kentcdodds/status/977018512689455106"&gt;March 23, 2018&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;&lt;h2&gt;Code Coverage &amp;lt; Use Case Coverage&lt;/h2&gt;&lt;p&gt;Code coverage is a metric that shows us what lines of our code is being run
during the tests. Let&amp;#x27;s use this code as an example:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;function arrayify(maybeArray) {
if (Array.isArray(maybeArray)) {
return maybeArray
} else if (!maybeArray) {
return []
} else {
return [maybeArray]
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Right now, we have no tests for this function, so our code coverage report will
indicate that we have &lt;code&gt;0%&lt;/code&gt; coverage of this function. The code coverage report
in this case helps give us an idea that tests are needed, but it does NOT tell
us what&amp;#x27;s important about this function, &lt;strong&gt;nor does it tell us the use cases
this function supports&lt;/strong&gt; which is the most important consideration we keep in
mind as we write tests.&lt;/p&gt;&lt;p&gt;In fact, when considering an entire application and wondering what to test, the
coverage report does a very poor job of giving us insight into where we should
be spending most of our time.&lt;/p&gt;&lt;p&gt;So the coverage report helps us identify what code in our codebase is missing
tests. So when you look at a code coverage report and note the lines that are
missing tests, don&amp;#x27;t think about the ifs/elses, loops, or lifecycles. Instead
ask yourself:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;What use cases are these lines of code supporting, and what tests can I add to
support those use cases?&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&amp;quot;Use Case Coverage&amp;quot; tells us how many of the use cases our tests support.
Unfortunately, there&amp;#x27;s no such thing as an automated &amp;quot;Use Case Coverage Report.&amp;quot;
We have to make that up ourselves. But the code coverage report can sometimes
help us identify use cases that we&amp;#x27;re not covering. Let&amp;#x27;s try it out.&lt;/p&gt;&lt;p&gt;So if we read at the code and consider it for a minute, we can identify our
first use case to support: &amp;quot;it returns an array if given an array.&amp;quot; This use
case statement is actually a great title for our test.&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;test(&amp;#x27;returns an array if given an array&amp;#x27;, () =&amp;gt; {
expect(arrayify([&amp;#x27;Elephant&amp;#x27;, &amp;#x27;Giraffe&amp;#x27;])).toEqual([&amp;#x27;Elephant&amp;#x27;, &amp;#x27;Giraffe&amp;#x27;])
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And with that test in place, our coverage report looks something like this
(highlighted lines are covered):&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript" metastring="{1-3}"&gt;function arrayify(maybeArray) {
if (Array.isArray(maybeArray)) {
return maybeArray
} else if (!maybeArray) {
return []
} else {
return [maybeArray]
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now, we can look at the remaining lines and determine that there are two more
use cases that our tests don&amp;#x27;t support yet:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;it returns an empty array if given a falsy value&lt;/li&gt;&lt;li&gt;it returns an array with the given argument if it&amp;#x27;s not an array or falsy&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Let&amp;#x27;s add tests for those use cases and see how it effects the code coverage.&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;test(&amp;#x27;returns an empty array if given a falsy value&amp;#x27;, () =&amp;gt; {
expect(arrayify()).toEqual([])
})
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class="language-javascript" metastring="{1-5}"&gt;function arrayify(maybeArray) {
if (Array.isArray(maybeArray)) {
return maybeArray
} else if (!maybeArray) {
return []
} else {
return [maybeArray]
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Nice, almost there!&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;test(`returns an array with the given argument if it&amp;#x27;s not an array or falsy`, () =&amp;gt; {
expect(arrayify(&amp;#x27;Leopard&amp;#x27;)).toEqual([&amp;#x27;Leopard&amp;#x27;])
})
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class="language-javascript" metastring="{1-9}"&gt;function arrayify(maybeArray) {
if (Array.isArray(maybeArray)) {
return maybeArray
} else if (!maybeArray) {
return []
} else {
return [maybeArray]
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Cool! Now we can be confident that so long as we don&amp;#x27;t need to change the use
cases of this function, our tests will continue to pass.&lt;/p&gt;&lt;p&gt;Code coverage is not a perfect metric, but it can be a useful tool in
identifying what parts of our codebase are missing &amp;quot;use case coverage&amp;quot;.&lt;/p&gt;&lt;h2&gt;Code coverage can hide use cases&lt;/h2&gt;&lt;p&gt;Sometimes, our code coverage report indicates 100% code coverage, but not 100%
use case coverage. This is why sometimes I try to think of all the use cases
before I even start writing the tests.&lt;/p&gt;&lt;p&gt;For example, let&amp;#x27;s imagine that the &lt;code&gt;arrayify&lt;/code&gt; function had been implemented
like this instead:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;function arrayify(maybeArray) {
if (Array.isArray(maybeArray)) {
return maybeArray
} else {
return [maybeArray].filter(Boolean)
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With that, we can get 100% coverage with the following two use cases:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;it returns an array if given an array&lt;/li&gt;&lt;li&gt;it returns an array with the given argument if it&amp;#x27;s not an array&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;But if we could look at a &lt;em&gt;use case&lt;/em&gt; coverage report, it would indicate that
we&amp;#x27;re missing this use case:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;it returns an empty array if given a falsy value&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;This could be bad because now our tests aren&amp;#x27;t giving us as much confidence that
our code will work when users use it like this: &lt;code&gt;arrayify()&lt;/code&gt;. Right now, it&amp;#x27;s
fine because even though we don&amp;#x27;t have a test for it, our code supports that use
case. But the reason we have tests in place is to ensure that code continues to
support the use cases we intend it to support, even as things change.&lt;/p&gt;&lt;p&gt;So, as an example for how missing this test can go wrong, someone could come
around, see that &lt;code&gt;.filter(Boolean)&lt;/code&gt; thing and think: &amp;quot;Huh, that&amp;#x27;s weird... I
wonder if we really need that.&amp;quot; So they remove it, and our tests continue to
pass, but any code that relied on the falsy behavior is now broken.&lt;/p&gt;&lt;p&gt;Key takeaway: &lt;strong&gt;Test use cases, not code.&lt;/strong&gt;&lt;/p&gt;&lt;h2&gt;How does this apply to React?&lt;/h2&gt;&lt;p&gt;When writing code, remember that you already have two users that you need to
support: End users, and developer users. Again, if you think about the code
rather than the use cases, it becomes dangerously natural to start testing
implementation details. When you do that, your code now has a third user.&lt;/p&gt;&lt;p&gt;Here are a few aspects of React that people often think about testing which
results in implementation details tests. For all of these, rather than thinking
about the code, think about the observable effect that code has for the end user
and developer user, that&amp;#x27;s your use case, test that.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Lifecycle methods&lt;/li&gt;&lt;li&gt;Element event handlers&lt;/li&gt;&lt;li&gt;Internal Component State&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Conversely, here are things that you should be testing because they concern your
two users. Each of these could change the DOM, make HTTP requests, call a
callback prop, or perform any other number of &lt;em&gt;observable&lt;/em&gt; side effects which
would be useful to test:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;User interactions (using
&lt;a href="https://testing-library.com/docs/dom-testing-library/api-events"&gt;&lt;code&gt;fireEvent&lt;/code&gt;&lt;/a&gt;
from react-testing-library): Is the end user able to interact with the
elements that the component renders?&lt;/li&gt;&lt;li&gt;Changing props (using
&lt;a href="https://testing-library.com/docs/react-testing-library/api#rerender"&gt;&lt;code&gt;rerender&lt;/code&gt;&lt;/a&gt;
from react-testing-library): What happens when the developer user re-renders
your component with new props?&lt;/li&gt;&lt;li&gt;Context changes (using
&lt;a href="https://testing-library.com/docs/react-testing-library/api#rerender"&gt;&lt;code&gt;rerender&lt;/code&gt;&lt;/a&gt;
from react-testing-library): What happens when the developer user changes
context resulting in your component re-rendering?&lt;/li&gt;&lt;li&gt;Subscription changes: What happens when an event emitter the component
subscribes to changes? (Like firebase, a redux store, a router, a media query,
or DOM-based subscriptions like online status)&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;How do I know where to start in an app?&lt;/h2&gt;&lt;p&gt;So we know how to think about what to test for individual components and even
pages of our app, but where do you start? It&amp;#x27;s a bit overwhelming. Especially if
you&amp;#x27;re just getting started with testing in a large app.&lt;/p&gt;&lt;p&gt;So here&amp;#x27;s what you do, consider your app from the user&amp;#x27;s point of view and ask:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;What part of this app would make me most upset if it were broken?&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Alternatively, and more generally:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;What would be the worst thing to break in this app?&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I&amp;#x27;d suggest making a list of features that your application supports and
prioritize them based on this criteria. It&amp;#x27;s a great exercise to do with your
team and manager. This meeting will have the side-effect of helping everyone in
the room understand the importance of testing and hopefully convince them that
it should receive some level of prioritization in all the other feature work you
need to do.&lt;/p&gt;&lt;p&gt;Once you have that prioritized list, then I suggest writing a single end to end
(E2E) test to cover the &amp;quot;happy path&amp;quot; that most of your users go through for the
particular use case. Often you can cover parts of several of the top features on
your list this way. This may take a little while to get set up, but it&amp;#x27;ll give
you a HUGE bang for your buck.&lt;/p&gt;&lt;p&gt;The E2E tests aren&amp;#x27;t going to give you 100% use case coverage (and you should
not even try), nor will they give you 100% code coverage (and you should not
even record that for E2E tests anyway), but it will give you a great starting
point and boost your confidence big time.&lt;/p&gt;&lt;p&gt;Once you have a few E2E tests in place, then you can start looking at writing
some integration tests for some of the edge cases that you are missing in your
E2E tests and unit tests for the more complex business logic that those features
are using. From here it just becomes a matter of adding tests over time. Just
don&amp;#x27;t bother with targeting a 100% code coverage report, it&amp;#x27;s not worth the
time.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;For more on establishing a culture of testing and reasonable code coverage
targets, I suggest watching &lt;a href="https://twitter.com/aarondjents"&gt;Aaron Abramov&amp;#x27;s&lt;/a&gt;
talk at &lt;a href="https://2018.assertjs.com"&gt;AssertJS 2018&lt;/a&gt;:
&lt;a href="https://youtu.be/_pnW-JjmyXE?list=PLZ66c9_z3umNSrKSb5cmpxdXZcIPNvKGw"&gt;Establishing testing patterns with software design principles&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;Read more about the distinction between the different types of tests here:
&lt;a href="https://kentcdodds.com/blog/unit-vs-integration-vs-e2e-tests"&gt;Static vs Unit vs Integration vs E2E Testing for Frontend Apps&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;Given enough time and experience, you develop an intuition for knowing what to
test. You&amp;#x27;ll probably make mistakes and struggle a bit. Don&amp;#x27;t give up! Keep
going. Good luck.&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/how-to-know-what-to-test"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[AHA Testing 💡]]></title>
<description><![CDATA[The AHA Programming Principle stands for "Avoid Hasty
Abstraction." I have specific feelings about how this applies to writing
maintainable tests. Most of the tests that I've seen in the wild have been
wildly on one side of the spectrum of…]]></description>
<link>https://kentcdodds.com/blog/aha-testing</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/aha-testing</guid>
<pubDate>Sun, 07 Apr 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;The &lt;a href="https://kentcdodds.com/blog/aha-programming"&gt;AHA Programming Principle&lt;/a&gt; stands for &amp;quot;Avoid Hasty
Abstraction.&amp;quot; I have specific feelings about how this applies to writing
maintainable tests. Most of the tests that I&amp;#x27;ve seen in the wild have been
wildly on one side of the spectrum of abstraction: ANA (Absolutely No
Abstraction), or completely DRY (Don&amp;#x27;t Repeat Yourself). (I made up ANA just
now).&lt;/p&gt;&lt;style data-emotion-css="22jbx"&gt;.css-22jbx{width:100%;margin-top:10px;margin-bottom:40px;}&lt;/style&gt;&lt;div class="css-22jbx"&gt;&lt;style data-emotion-css="se5o5n"&gt;.css-se5o5n{width:100%;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;font-size:1.5em;text-align:center;line-height:1.2;margin-bottom:4px;}.css-se5o5n small,.css-se5o5n strong{display:block;}.css-se5o5n small{font-size:0.5em;}&lt;/style&gt;&lt;div class="css-se5o5n"&gt;&lt;style data-emotion-css="1u45wx3"&gt;.css-1u45wx3{color:rgb(94,49,220);}&lt;/style&gt;&lt;div class="css-1u45wx3"&gt;&lt;strong&gt;ANA&lt;/strong&gt;&lt;small&gt;(Absolutely No Abstraction)&lt;/small&gt;&lt;/div&gt;&lt;style data-emotion-css="1q25q80"&gt;.css-1q25q80{color:rgb(71,67,220);}&lt;/style&gt;&lt;div class="css-1q25q80"&gt;&lt;strong&gt;AHA&lt;/strong&gt;&lt;small&gt;(Avoid Hasty Abstraction)&lt;/small&gt;&lt;/div&gt;&lt;style data-emotion-css="dshstu"&gt;.css-dshstu{color:rgb(49,85,220);}&lt;/style&gt;&lt;div class="css-dshstu"&gt;&lt;strong&gt;DRY&lt;/strong&gt;&lt;small&gt;(Don&amp;#x27;t Repeat Yourself)&lt;/small&gt;&lt;/div&gt;&lt;/div&gt;&lt;style data-emotion-css="r191zs"&gt;.css-r191zs{width:100%;height:20px;background-image:linear-gradient(-213deg,rgb(94,49,220) 0%,rgb(49,85,220) 100%);}&lt;/style&gt;&lt;div class="css-r191zs"&gt;&lt;/div&gt;&lt;style data-emotion-css="1u3gm1r"&gt;.css-1u3gm1r{margin-top:10px;color:rgb(71,67,220);background:linear-gradient(-213deg,rgb(94,49,220) 0%,rgb(49,85,220) 100%);-webkit-background-clip:text;-webkit-text-fill-color:transparent;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;font-size:1.8em;}@media (max-width:767px){.css-1u3gm1r{font-size:1em;}}&lt;/style&gt;&lt;div class="css-1u3gm1r"&gt;&lt;strong&gt;T&lt;/strong&gt;&lt;strong&gt;h&lt;/strong&gt;&lt;strong&gt;e&lt;/strong&gt;&lt;strong&gt;&lt;/strong&gt;&lt;strong&gt;S&lt;/strong&gt;&lt;strong&gt;p&lt;/strong&gt;&lt;strong&gt;e&lt;/strong&gt;&lt;strong&gt;c&lt;/strong&gt;&lt;strong&gt;t&lt;/strong&gt;&lt;strong&gt;r&lt;/strong&gt;&lt;strong&gt;u&lt;/strong&gt;&lt;strong&gt;m&lt;/strong&gt;&lt;strong&gt;&lt;/strong&gt;&lt;strong&gt;o&lt;/strong&gt;&lt;strong&gt;f&lt;/strong&gt;&lt;strong&gt;&lt;/strong&gt;&lt;strong&gt;A&lt;/strong&gt;&lt;strong&gt;b&lt;/strong&gt;&lt;strong&gt;s&lt;/strong&gt;&lt;strong&gt;t&lt;/strong&gt;&lt;strong&gt;r&lt;/strong&gt;&lt;strong&gt;a&lt;/strong&gt;&lt;strong&gt;c&lt;/strong&gt;&lt;strong&gt;t&lt;/strong&gt;&lt;strong&gt;i&lt;/strong&gt;&lt;strong&gt;o&lt;/strong&gt;&lt;strong&gt;n&lt;/strong&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Finding a sweet spot in the middle of the spectrum of abstraction is key to
developing maintainable tests.&lt;/p&gt;&lt;h2&gt;ANA Testing&lt;/h2&gt;&lt;p&gt;The best example of &amp;quot;Absolutely No Abstraction&amp;quot; I&amp;#x27;ve seen in testing is for
&lt;a href="https://expressjs.com/en/guide/routing.html"&gt;ExpressJS route handlers&lt;/a&gt;. For you
to understand what I mean when I say &amp;quot;ANA is bad for testing&amp;quot; I&amp;#x27;m going to give
you a typical test file and ask you to pretend you&amp;#x27;re going to maintain this
codebase and these tests. It&amp;#x27;s important for you to understand how this route
works. You&amp;#x27;re relieved that there are tests in place which will help you make
sure you&amp;#x27;re not going to break something. So now you&amp;#x27;re going to use the tests
to understand the nuances of the route handler.&lt;/p&gt;&lt;p&gt;Try to read this test and understand the one nuance between the two of them.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Don&amp;#x27;t spend too long on this...&lt;/p&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;import * as blogPostController from &amp;#x27;../blog-post&amp;#x27;
// load the application-wide mock for the database.
// I guess that means this is AANA (Almost Absolutely No Abstraction)
// but I didn&amp;#x27;t want to write out a whole db mock for this blog post 😅
jest.mock(&amp;#x27;../../lib/db&amp;#x27;)
test(&amp;#x27;lists blog posts for the logged in user&amp;#x27;, async () =&amp;gt; {
const req = {
locale: {
source: &amp;#x27;default&amp;#x27;,
language: &amp;#x27;en&amp;#x27;,
region: &amp;#x27;GB&amp;#x27;,
},
user: {
guid: &amp;#x27;0336397b-e29d-4b63-b94d-7e68a6fa3747&amp;#x27;,
isActive: false,
picture: &amp;#x27;http://placehold.it/32x32&amp;#x27;,
age: 30,
name: {
first: &amp;#x27;Francine&amp;#x27;,
last: &amp;#x27;Oconnor&amp;#x27;,
},
company: &amp;#x27;ACME&amp;#x27;,
email: &amp;#x27;francine.oconnor@ac.me&amp;#x27;,
latitude: 51.507351,
longitude: -0.127758,
favoriteFruit: &amp;#x27;banana&amp;#x27;,
},
body: {},
cookies: {},
query: {},
params: {
bucket: &amp;#x27;photography&amp;#x27;,
},
header(name) {
return {
Authorization: &amp;#x27;Bearer TEST_TOKEN&amp;#x27;,
}[name]
},
}
const res = {
clearCookie: jest.fn(),
cookie: jest.fn(),
end: jest.fn(),
locals: {
content: {},
},
json: jest.fn(),
send: jest.fn(),
sendStatus: jest.fn(),
set: jest.fn(),
}
const next = jest.fn()
await blogPostController.loadBlogPosts(req, res, next)
expect(res.json).toHaveBeenCalledTimes(1)
expect(res.json).toHaveBeenCalledWith({
posts: expect.arrayContaining([
expect.objectContaining({
title: &amp;#x27;Test Post 1&amp;#x27;,
subtitle: &amp;#x27;This is the subtitle of Test Post 1&amp;#x27;,
body: &amp;#x27;The is the body of Test Post 1&amp;#x27;,
}),
]),
})
})
test(&amp;#x27;returns an empty list when there are no blog posts&amp;#x27;, async () =&amp;gt; {
const req = {
locale: {
source: &amp;#x27;default&amp;#x27;,
language: &amp;#x27;en&amp;#x27;,
region: &amp;#x27;GB&amp;#x27;,
},
user: {
guid: &amp;#x27;0336397b-e29d-4b63-b94d-7e68a6fa3747&amp;#x27;,
isActive: false,
picture: &amp;#x27;http://placehold.it/32x32&amp;#x27;,
age: 30,
name: {
first: &amp;#x27;Francine&amp;#x27;,
last: &amp;#x27;Oconnor&amp;#x27;,
},
company: &amp;#x27;ACME&amp;#x27;,
email: &amp;#x27;francine.oconnor@ac.me&amp;#x27;,
latitude: 31.230416,
longitude: 121.473701,
favoriteFruit: &amp;#x27;banana&amp;#x27;,
},
body: {},
cookies: {},
query: {},
params: {
bucket: &amp;#x27;photography&amp;#x27;,
},
header(name) {
return {
Authorization: &amp;#x27;Bearer TEST_TOKEN&amp;#x27;,
}[name]
},
}
const res = {
clearCookie: jest.fn(),
cookie: jest.fn(),
end: jest.fn(),
locals: {
content: {},
},
json: jest.fn(),
send: jest.fn(),
sendStatus: jest.fn(),
set: jest.fn(),
}
const next = jest.fn()
await blogPostController.loadBlogPosts(req, res, next)
expect(res.json).toHaveBeenCalledTimes(1)
expect(res.json).toHaveBeenCalledWith({
posts: [],
})
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Did you find the difference? Yeah! We expect to find a post in the first one and
not in the second one! Cool! Great job. But... what causes that? Why does
&lt;code&gt;blogPostController.loadBlogPosts(req, res, next)&lt;/code&gt; call &lt;code&gt;res.json&lt;/code&gt; with a blog
post in the first one and not in the second one?&lt;/p&gt;&lt;p&gt;If you didn&amp;#x27;t figure that out, don&amp;#x27;t feel bad and don&amp;#x27;t worry, I&amp;#x27;ll show you
later. If you did, you&amp;#x27;re probably really good at
&lt;a href="https://en.wikipedia.org/wiki/Where%27s_Wally%3F"&gt;&amp;quot;Where&amp;#x27;s Wally&amp;quot;&lt;/a&gt; and that&amp;#x27;s
my point. Tests like this make it harder than it needs to be to understand and
maintain the tests.&lt;/p&gt;&lt;p&gt;Now imagine that there are twenty such tests in a single file. You think it&amp;#x27;s
terrible? Yes, it&amp;#x27;s pretty bad. Never seen tests like this before? You&amp;#x27;re lucky!
I&amp;#x27;ve seen it a lot. Here&amp;#x27;s how it gets this way:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Engineer Joe joins a team&lt;/li&gt;&lt;li&gt;Joe needs to add a test&lt;/li&gt;&lt;li&gt;Joe copies a previous test that looks like what they need and modifies it for
their use case.&lt;/li&gt;&lt;li&gt;Reviewers observe that the tests pass and assume Joe knows what they&amp;#x27;re
talking about.&lt;/li&gt;&lt;li&gt;PR is merged.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Here&amp;#x27;s your litmus test:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;How easy is it to determine the difference between assertions of two similar
tests and what causes that difference?&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Absolutely No Abstraction testing makes this very difficult.&lt;/p&gt;&lt;h2&gt;DRY Testing&lt;/h2&gt;&lt;p&gt;I don&amp;#x27;t have time at the moment to give you a good example of a &lt;code&gt;DRY&lt;/code&gt; test. Just
know that often what happens when people apply &lt;code&gt;DRY&lt;/code&gt; to anything they typically
wind up being harder to maintain due to this process:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Engineer Joe joins a team&lt;/li&gt;&lt;li&gt;Joe needs to add a test&lt;/li&gt;&lt;li&gt;Joes copies a previous test that looks basically exactly like what they need
and adds another &lt;code&gt;if&lt;/code&gt; statement to the testing utility for their case.&lt;/li&gt;&lt;li&gt;Reviewers observe that the tests pass and assume Joe knows what they&amp;#x27;re
talking about.&lt;/li&gt;&lt;li&gt;PR is merged.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Another thing that I see a lot in DRY testing is the overuse of &lt;code&gt;describe&lt;/code&gt; and
&lt;code&gt;it&lt;/code&gt; nesting + &lt;code&gt;beforeEach&lt;/code&gt;. The more you nest and use shared variables between
tests, the harder it is to follow the logic. I write about this problem a little
bit in &lt;a href="https://kentcdodds.com/blog/test-isolation-with-react"&gt;Test Isolation with React&lt;/a&gt; which I
recommend you read.&lt;/p&gt;&lt;h2&gt;AHA Testing&lt;/h2&gt;&lt;p&gt;That first test is absolutely screaming for abstraction (which is the guiding
principle for AHA programming). So let&amp;#x27;s write a thoughtful abstraction for that
test. Now try to figure out what makes the difference in these tests:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;import * as blogPostController from &amp;#x27;../blog-post&amp;#x27;
// load the application-wide mock for the database.
jest.mock(&amp;#x27;../../lib/db&amp;#x27;)
function setup(overrides = {}) {
const req = {
locale: {
source: &amp;#x27;default&amp;#x27;,
language: &amp;#x27;en&amp;#x27;,
region: &amp;#x27;GB&amp;#x27;,
},
user: {
guid: &amp;#x27;0336397b-e29d-4b63-b94d-7e68a6fa3747&amp;#x27;,
isActive: false,
picture: &amp;#x27;http://placehold.it/32x32&amp;#x27;,
age: 30,
name: {
first: &amp;#x27;Francine&amp;#x27;,
last: &amp;#x27;Oconnor&amp;#x27;,
},
company: &amp;#x27;ACME&amp;#x27;,
email: &amp;#x27;francine.oconnor@ac.me&amp;#x27;,
latitude: 51.507351,
longitude: -0.127758,
favoriteFruit: &amp;#x27;banana&amp;#x27;,
},
body: {},
cookies: {},
query: {},
params: {
bucket: &amp;#x27;photography&amp;#x27;,
},
header(name) {
return {
Authorization: &amp;#x27;Bearer TEST_TOKEN&amp;#x27;,
}[name]
},
}
const res = {
clearCookie: jest.fn(),
cookie: jest.fn(),
end: jest.fn(),
locals: {
content: {},
},
json: jest.fn(),
send: jest.fn(),
sendStatus: jest.fn(),
set: jest.fn(),
}
const next = jest.fn()
return {req, res, next}
}
test(&amp;#x27;lists blog posts for the logged in user&amp;#x27;, async () =&amp;gt; {
const {req, res, next} = setup()
await blogPostController.loadBlogPosts(req, res, next)
expect(res.json).toHaveBeenCalledTimes(1)
expect(res.json).toHaveBeenCalledWith({
posts: expect.arrayContaining([
expect.objectContaining({
title: &amp;#x27;Test Post 1&amp;#x27;,
subtitle: &amp;#x27;This is the subtitle of Test Post 1&amp;#x27;,
body: &amp;#x27;The is the body of Test Post 1&amp;#x27;,
}),
]),
})
})
test(&amp;#x27;returns an empty list when there are no blog posts&amp;#x27;, async () =&amp;gt; {
const {req, res, next} = setup()
req.user.latitude = 31.230416
req.user.longitude = 121.473701
await blogPostController.loadBlogPosts(req, res, next)
expect(res.json).toHaveBeenCalledTimes(1)
expect(res.json).toHaveBeenCalledWith({
posts: [],
})
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now can you tell? What&amp;#x27;s the difference between the first and the second test?
In the first our user is in London and in the second our user is in Shanghai!
Gee, sure would&amp;#x27;ve been nice if our co-workers had told us we were working on a
location-based blogging platform (hey... now that&amp;#x27;s an interesting product idea
🤔).&lt;/p&gt;&lt;p&gt;By adding just a little mindful abstraction, we&amp;#x27;ve been able to make it much
more clear what actually matters in the difference of the inputs and outputs
leading to tests which make a LOT more sense and are WAY easier to maintain.&lt;/p&gt;&lt;h2&gt;AHA Testing with React&lt;/h2&gt;&lt;p&gt;In a react world, I will sometimes have a &lt;code&gt;renderFoo&lt;/code&gt; function that acts like
the &lt;code&gt;setup&lt;/code&gt; function here. Here&amp;#x27;s a simple example:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;import React from &amp;#x27;react&amp;#x27;
import {render, fireEvent} from &amp;#x27;react-testing-library&amp;#x27;
import LoginForm from &amp;#x27;../login-form&amp;#x27;
function renderLoginForm(props) {
const utils = render(&amp;lt;LoginForm {...props} /&amp;gt;)
const usernameInput = utils.getByLabelText(/username/i)
const passwordInput = utils.getByLabelText(/password/i)
const submitButton = utils.getByText(/submit/i)
return {
...utils,
usernameInput,
passwordInput,
submitButton,
changeUsername: value =&amp;gt; fireEvent.change(usernameInput, {target: {value}}),
changePassword: value =&amp;gt; fireEvent.change(passwordInput, {target: {value}}),
submitForm: () =&amp;gt; fireEvent.click(submitButton),
}
}
test(&amp;#x27;submit calls the submit handler&amp;#x27;, () =&amp;gt; {
const handleSubmit = jest.fn()
const {changeUsername, changePassword, submitForm} = renderLoginForm({
onSubmit: handleSubmit,
})
const username = &amp;#x27;chucknorris&amp;#x27;
const password = &amp;#x27;ineednopassword&amp;#x27;
changeUsername(username)
changePassword(password)
submitForm()
expect(handleSubmit).toHaveBeenCalledTimes(1)
expect(handleSubmit).toHaveBeenCalledWith({username, password})
})
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;Note: I would consider this pre-mature abstraction if you&amp;#x27;ve only got two or
three tests in the file that is using it and those tests are short. But if
you&amp;#x27;ve got some nuance you&amp;#x27;re testing (like error states for example), then
this kind of abstraction is great.&lt;/p&gt;&lt;/blockquote&gt;&lt;h2&gt;jest-in-case and test.each&lt;/h2&gt;&lt;p&gt;If you&amp;#x27;re writing tests for a pure function, you&amp;#x27;re in luck because those are
often the easiest to test for. You can seriously simplify your tests by using a
simple abstraction that calls out VERY clearly the outputs and inputs.&lt;/p&gt;&lt;p&gt;For (contrived) example:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;import add from &amp;#x27;../add&amp;#x27;
test(&amp;#x27;adds one and two to equal three&amp;#x27;, () =&amp;gt; {
expect(add(1, 2)).toBe(3)
})
test(&amp;#x27;adds three and four to equal seven&amp;#x27;, () =&amp;gt; {
expect(add(3, 4)).toBe(7)
})
test(&amp;#x27;adds one hundred and two to equal one hundred two&amp;#x27;, () =&amp;gt; {
expect(add(100, 2)).toBe(102)
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That&amp;#x27;s pretty simple to follow, but it can be improved with &lt;code&gt;jest-in-case&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;import cases from &amp;#x27;jest-in-case&amp;#x27;
import add from &amp;#x27;../add&amp;#x27;
cases(
&amp;#x27;add&amp;#x27;,
({first, second, result}) =&amp;gt; {
expect(add(first, second)).toBe(result)
},
[
{first: 1, second: 2, result: 3},
{first: 3, second: 4, result: 7},
{first: 100, second: 2, result: 102},
],
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I probably wouldn&amp;#x27;t bother doing this for this simple example, but what&amp;#x27;s cool
about it is that you can add more test cases very easily by simply adding more
elements to that array. A good example of this concept (that actually &lt;em&gt;doesn&amp;#x27;t&lt;/em&gt;
use jest-in-case) is
&lt;a href="https://github.com/kentcdodds/rtl-css-js/blob/b148865ce6a4c994eba292015b8f44b5dae7edaa/src/__tests__/index.js"&gt;the &lt;code&gt;rtl-css-js&lt;/code&gt; tests&lt;/a&gt;.
Contributors to this codebase find it very easy to add new test cases with this
structure.&lt;/p&gt;&lt;p&gt;This can also be applied to impure functions and modules as well, though it
takes a little bit more work.
(&lt;a href="https://github.com/kentcdodds/kcd-scripts/blob/7bc29e41e46e73b4b57c0f975648a90a75c24c80/src/scripts/__tests__/lint.js"&gt;Here&amp;#x27;s a test that does this which I&amp;#x27;m not totally proud of, but it&amp;#x27;s not too bad&lt;/a&gt;)&lt;/p&gt;&lt;p&gt;I personally prefer &lt;a href="https://github.com/atlassian/jest-in-case"&gt;jest-in-case&lt;/a&gt;
but Jest has a built-in
&lt;a href="https://jestjs.io/docs/en/api#testeachtable-name-fn-timeout"&gt;&lt;code&gt;test.each&lt;/code&gt;&lt;/a&gt;
functionality that you may find useful.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;Certainly our tests could&amp;#x27;ve been improved by providing better names and/or
comments as well, but our simple &lt;code&gt;setup&lt;/code&gt; abstraction (by the way, that&amp;#x27;s called
a &amp;quot;Test Object Factory&amp;quot;) doesn&amp;#x27;t really need them. So my point is: &lt;strong&gt;it takes
less work to write and maintain tests that have mindful abstractions applied to
them.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;I hope that&amp;#x27;s helpful! Good luck!&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/aha-testing"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[AHA Programming 💡]]></title>
<description><![CDATA[DRY DRY (an acronym for "Don't Repeat Yourself") ,
is an old software principle that Wikipedia sums up like this: Every piece of knowledge must have a single, unambiguous, authoritative
representation within a system This is generally a good practice…]]></description>
<link>https://kentcdodds.com/blog/aha-programming</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/aha-programming</guid>
<pubDate>Sun, 31 Mar 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;h2&gt;DRY&lt;/h2&gt;&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself"&gt;DRY (an acronym for &amp;quot;Don&amp;#x27;t Repeat Yourself&amp;quot;)&lt;/a&gt;,
is an old software principle that Wikipedia sums up like this:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Every piece of knowledge must have a single, unambiguous, authoritative
representation within a system&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;This is generally a good practice that I typically subscribe to (though less
dogmatically than that definition seems to encourage). The biggest problem I&amp;#x27;ve
had with &lt;a href="https://en.wikipedia.org/wiki/Duplicate_code"&gt;code duplication&lt;/a&gt; (aka
copy/paste, it&amp;#x27;s basically the antithesis of &lt;code&gt;DRY&lt;/code&gt;) is discovering a bug in one
place, fixing it, then realizing that same bug was elsewhere and having to fix
it there as well.&lt;/p&gt;&lt;p&gt;Once, I inherited a codebase that made very heavy use of code duplication and
one time I had to fix a bug in eight different places! 😱 Talk about irritating!
Abstracting that code into a function that could be called anywhere it was
needed would&amp;#x27;ve helped out a LOT.&lt;/p&gt;&lt;h2&gt;WET&lt;/h2&gt;&lt;p&gt;There&amp;#x27;s another concept that people have referred to as &lt;code&gt;WET&lt;/code&gt; programming which
stands for &amp;quot;Write Everything Twice.&amp;quot; That&amp;#x27;s similarly dogmatic and over
prescriptive. &lt;a href="https://twitter.com/CallMeWuz"&gt;Conlin Durbin&lt;/a&gt;
&lt;a href="https://dev.to/wuz/stop-trying-to-be-so-dry-instead-write-everything-twice-wet-5g33"&gt;has defined this as&lt;/a&gt;:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;You can ask yourself &amp;quot;Haven&amp;#x27;t I written this before?&amp;quot; two times, but never
three.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;In that same codebase I mentioned above, there was some over-abstraction that
was even more harmful than duplication. It was AngularJS code and for several
AngularJS controllers, the code passed &lt;code&gt;this&lt;/code&gt; to a function which would
monkey-patch methods and properties onto &lt;code&gt;this&lt;/code&gt; in a way enhancing the
controller instance with certain abilities. A sort of pseudo-inheritance thing I
guess. It was SUPER confusing, hard to follow, and I was terrified to make any
changes to that area of the codebase.&lt;/p&gt;&lt;p&gt;The code &lt;em&gt;was&lt;/em&gt; reused in lots more than three places, but the abstraction was
bad and I wished that the code had been duplicated instead.&lt;/p&gt;&lt;h2&gt;AHA 💡&lt;/h2&gt;&lt;p&gt;&lt;code&gt;AHA&lt;/code&gt; (pronounced &amp;quot;Aha!&amp;quot; like you just made a discovery) is an acronym I
&lt;a href="https://twitter.com/codehitchhiker/status/1112819136147742720"&gt;got from&lt;/a&gt;
&lt;a href="https://twitter.com/codehitchhiker"&gt;Cher&lt;/a&gt; which stands for&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Avoid Hasty Abstractions&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;The way I think of this principle is beautifully described by
&lt;a href="https://twitter.com/sandimetz"&gt;Sandi Metz&lt;/a&gt; who
&lt;a href="https://www.sandimetz.com/blog/2016/1/20/the-wrong-abstraction"&gt;wrote&lt;/a&gt;:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;prefer duplication over the wrong abstraction&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;This is such a solid golden nugget of wisdom that I want you to read it again,
then read Sandi&amp;#x27;s blog post on the subject:
&lt;a href="https://www.sandimetz.com/blog/2016/1/20/the-wrong-abstraction"&gt;The Wrong Abstraction&lt;/a&gt;.
It&amp;#x27;s fantastic.&lt;/p&gt;&lt;p&gt;Here&amp;#x27;s another important related principle that I want to add:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Optimize for change first&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I think the key is that we don&amp;#x27;t know what the future of code will be. We could
spend weeks optimizing code for performance, or coming up with the best API for
our new abstraction, only to find out the next day that we made incorrect
assumptions and the API needs a complete rework or the feature the code was
written for is no longer needed. We don&amp;#x27;t know for sure. All we can really be
sure of is that things will probably change, and if they never do then we wont
touch the code anyway so who cares what it looks like?&lt;/p&gt;&lt;p&gt;Now, don&amp;#x27;t get me wrong, I&amp;#x27;m not suggesting anarchy. I&amp;#x27;m just suggesting that we
should be mindful of the fact that we don&amp;#x27;t &lt;em&gt;really&lt;/em&gt; know what requirements will
be placed upon our code in the future.&lt;/p&gt;&lt;p&gt;So I&amp;#x27;m fine with code duplication until you feel pretty confident that you know
the use cases for that duplicate code. What parts of the code are different that
would make good arguments to your function? After you&amp;#x27;ve got a few places where
that code is running, the commonalities will scream at you for abstraction and
you&amp;#x27;ll be in the right frame of mind to provide that abstraction.&lt;/p&gt;&lt;p&gt;If you abstract early though, you&amp;#x27;ll think the function or component is perfect
for your use case and so you just bend the code to fit your new use case. This
goes on several times until the abstraction is basically your whole application
in &lt;code&gt;if&lt;/code&gt; statements and loops 😂😭&lt;/p&gt;&lt;p&gt;&lt;strong&gt;I think the big takeaway&lt;/strong&gt; about &amp;quot;AHA Programming&amp;quot; is that you shouldn&amp;#x27;t be
dogmatic about when you start writing abstractions but instead write the
abstraction when it &lt;em&gt;feels&lt;/em&gt; right and don&amp;#x27;t be afraid to duplicate code until
you get there.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;I feel like a measured and pragmatic approach to software principles is
important. That&amp;#x27;s why I prefer &lt;code&gt;AHA&lt;/code&gt; over &lt;code&gt;DRY&lt;/code&gt; or &lt;code&gt;WET&lt;/code&gt;. It&amp;#x27;s intended to help
you be mindful of your abstractions without giving hard-fast rules to when it is
or isn&amp;#x27;t ok to abstract some code into a function or module.&lt;/p&gt;&lt;p&gt;I hope that&amp;#x27;s helpful to you. If you find yourself mired in bad abstractions,
take heart! Sandi gives you some good steps for how to get out of that!
&lt;a href="https://www.sandimetz.com/blog/2016/1/20/the-wrong-abstraction"&gt;Just read her blog post&lt;/a&gt;.
Good luck!&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/aha-programming"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[The State Reducer Pattern with React Hooks]]></title>
<description><![CDATA[Some History About a year ago, I developed a new pattern for enhancing your React components
called the state reducer pattern . I used it
in downshift to enable an awesome
API for people who wanted to make changes to how downshift updates state…]]></description>
<link>https://kentcdodds.com/blog/the-state-reducer-pattern-with-react-hooks</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/the-state-reducer-pattern-with-react-hooks</guid>
<pubDate>Mon, 25 Mar 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;h2&gt;Some History&lt;/h2&gt;&lt;p&gt;About a year ago, I developed a new pattern for enhancing your React components
called &lt;a href="https://kentcdodds.com/blog/the-state-reducer-pattern"&gt;the state reducer pattern&lt;/a&gt;. I used it
in &lt;a href="https://github.com/downshift-js/downshift"&gt;downshift&lt;/a&gt; to enable an awesome
API for people who wanted to make changes to how downshift updates state
internally.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;If you&amp;#x27;re unfamiliar with downshift, just know that it&amp;#x27;s an &amp;quot;enhanced input&amp;quot;
component that allows you to build things like accessible
autocomplete/typeahead/dropdown components. It&amp;#x27;s important to know that it
manages the following items of state: &lt;code&gt;isOpen&lt;/code&gt;, &lt;code&gt;selectedItem&lt;/code&gt;,
&lt;code&gt;highlightedIndex&lt;/code&gt;, and &lt;code&gt;inputValue&lt;/code&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Downshift is currently implemented as a render prop component, because at the
time, render props was the best way to make a
&lt;a href="https://www.merrickchristensen.com/articles/headless-user-interface-components"&gt;&amp;quot;Headless UI Component&amp;quot;&lt;/a&gt;
(typically implemented via a &amp;quot;render prop&amp;quot; API) which made it possible for you
to share logic without being opinionated about the UI. This is the major reason
that downshift is so successful.&lt;/p&gt;&lt;p&gt;Today however, we have &lt;a href="https://reactjs.org/hooks"&gt;React Hooks&lt;/a&gt; and
&lt;a href="https://kentcdodds.com/blog/react-hooks-whats-going-to-happen-to-render-props"&gt;hooks are way better at doing this than render props&lt;/a&gt;.
So I thought I&amp;#x27;d give you all an update of how this pattern transfers over to
this new API the React team has given us. (Note:
&lt;a href="https://github.com/downshift-js/downshift/issues/683"&gt;Downshift has plans to implement a hook&lt;/a&gt;)&lt;/p&gt;&lt;p&gt;As a reminder, the benefit of the state reducer pattern is in the fact that it
allows
&lt;a href="https://en.wikipedia.org/wiki/Inversion_of_control"&gt;&amp;quot;inversion of control&amp;quot;&lt;/a&gt;
which is basically a mechanism for the author of the API to allow the user of
the API to control how things work internally. For an example-based talk about
this, I strongly recommend you give my React Rally 2018 talk a watch:&lt;/p&gt;&lt;p&gt;&lt;iframe width="100%" height="315" src="https://www.youtube-nocookie.com/embed/AiJ8tRRH0f8?rel=0&amp;amp;list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf" frameBorder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""&gt;&lt;/iframe&gt;&lt;/p&gt;&lt;p&gt;So in the downshift example, I had made the decision that when an end user
selects an item, the &lt;code&gt;isOpen&lt;/code&gt; should be set to &lt;code&gt;false&lt;/code&gt; (and the menu should be
closed). Someone was building a multi-select with downshift and wanted to keep
the menu open after the user selects an item in the menu (so they can continue
to select more).&lt;/p&gt;&lt;p&gt;By inverting control of state updates with the state reducer pattern, I was able
to enable their use case as well as any other use case people could possibly
want when they want to change how downshift operates internally. Inversion of
control is an enabling computer science principle and the state reducer pattern
is an awesome implementation of that idea that translates even better to hooks
than it did to regular components.&lt;/p&gt;&lt;h2&gt;Using a State Reducer with Hooks&lt;/h2&gt;&lt;p&gt;Ok, so the concept goes like this:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;End user does an action&lt;/li&gt;&lt;li&gt;Dev calls dispatch&lt;/li&gt;&lt;li&gt;Hook determines the necessary changes&lt;/li&gt;&lt;li&gt;Hook calls dev&amp;#x27;s code for further changes 👈 this is the inversion of control
part&lt;/li&gt;&lt;li&gt;Hook makes the state changes&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;strong&gt;WARNING: Contrived example ahead&lt;/strong&gt;: To keep things simple, I&amp;#x27;m going to use a
simple &lt;code&gt;useToggle&lt;/code&gt; hook and component as a starting point. It&amp;#x27;ll feel contrived,
but I don&amp;#x27;t want you to get distracted by a complicated example as I teach you
how to use this pattern with hooks. Just know that this pattern works best when
it&amp;#x27;s applied to complex hooks and components (like downshift).&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;function useToggle() {
const [on, setOnState] = React.useState(false)
const toggle = () =&amp;gt; setOnState(o =&amp;gt; !o)
const setOn = () =&amp;gt; setOnState(true)
const setOff = () =&amp;gt; setOnState(false)
return {on, toggle, setOn, setOff}
}
function Toggle() {
const {on, toggle, setOn, setOff} = useToggle()
return (
&amp;lt;div&amp;gt;
&amp;lt;button onClick={setOff}&amp;gt;Switch Off&amp;lt;/button&amp;gt;
&amp;lt;button onClick={setOn}&amp;gt;Switch On&amp;lt;/button&amp;gt;
&amp;lt;Switch on={on} onClick={toggle} /&amp;gt;
&amp;lt;/div&amp;gt;
)
}
function App() {
return &amp;lt;Toggle /&amp;gt;
}
ReactDOM.render(&amp;lt;App /&amp;gt;, document.getElementById(&amp;#x27;root&amp;#x27;))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now, let&amp;#x27;s say we wanted to adjust the &lt;code&gt;&amp;lt;Toggle /&amp;gt;&lt;/code&gt; component so the user
couldn&amp;#x27;t click the &lt;code&gt;&amp;lt;Switch /&amp;gt;&lt;/code&gt; more than 4 times in a row unless they click a
&amp;quot;Reset&amp;quot; button:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx" metastring="{2-3,7-10,16-19}"&gt;function Toggle() {
const [clicksSinceReset, setClicksSinceReset] = React.useState(0)
const tooManyClicks = clicksSinceReset &amp;gt;= 4
const {on, toggle, setOn, setOff} = useToggle()
function handleClick() {
toggle()
setClicksSinceReset(count =&amp;gt; count + 1)
}
return (
&amp;lt;div&amp;gt;
&amp;lt;button onClick={setOff}&amp;gt;Switch Off&amp;lt;/button&amp;gt;
&amp;lt;button onClick={setOn}&amp;gt;Switch On&amp;lt;/button&amp;gt;
&amp;lt;Switch on={on} onClick={handleClick} /&amp;gt;
{tooManyClicks ? (
&amp;lt;button onClick={() =&amp;gt; setClicksSinceReset(0)}&amp;gt;Reset&amp;lt;/button&amp;gt;
) : null}
&amp;lt;/div&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Cool, so an easy solution to this problem would be to add an if statement in the
&lt;code&gt;handleClick&lt;/code&gt; function and not call &lt;code&gt;toggle&lt;/code&gt; if &lt;code&gt;tooManyClicks&lt;/code&gt; is true, but
let&amp;#x27;s keep going for the purposes of this example.&lt;/p&gt;&lt;p&gt;How could we change the &lt;code&gt;useToggle&lt;/code&gt; hook, to &lt;em&gt;invert control&lt;/em&gt; in this situation?
Let&amp;#x27;s think about the API first, then the implementation second. As a user, it&amp;#x27;d
be cool if I could hook into every state update before it actually happens and
modify it, like so:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx" metastring="{6-14}"&gt;function Toggle() {
const [clicksSinceReset, setClicksSinceReset] = React.useState(0)
const tooManyClicks = clicksSinceReset &amp;gt;= 4
const {on, toggle, setOn, setOff} = useToggle({
modifyStateChange(currentState, changes) {
if (tooManyClicks) {
// other changes are fine, but on needs to be unchanged
return {...changes, on: currentState.on}
} else {
// the changes are fine
return changes
}
},
})
function handleClick() {
toggle()
setClicksSinceReset(count =&amp;gt; count + 1)
}
return (
&amp;lt;div&amp;gt;
&amp;lt;button onClick={setOff}&amp;gt;Switch Off&amp;lt;/button&amp;gt;
&amp;lt;button onClick={setOn}&amp;gt;Switch On&amp;lt;/button&amp;gt;
&amp;lt;Switch on={on} onClick={handleClick} /&amp;gt;
{tooManyClicks ? (
&amp;lt;button onClick={() =&amp;gt; setClicksSinceReset(0)}&amp;gt;Reset&amp;lt;/button&amp;gt;
) : null}
&amp;lt;/div&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So that&amp;#x27;s great, except it prevents changes from happening when people click the
&amp;quot;Switch Off&amp;quot; or &amp;quot;Switch On&amp;quot; buttons, and we only want to prevent the
&lt;code&gt;&amp;lt;Switch /&amp;gt;&lt;/code&gt; from toggling the state.&lt;/p&gt;&lt;p&gt;Hmmm... What if we change &lt;code&gt;modifyStateChange&lt;/code&gt; to be called &lt;code&gt;reducer&lt;/code&gt; and it
accepts an &lt;code&gt;action&lt;/code&gt; as the second argument? Then the &lt;code&gt;action&lt;/code&gt; could have a
&lt;code&gt;type&lt;/code&gt; that determines what type of change is happening, and the &lt;code&gt;changes&lt;/code&gt; could
just be a property on that object. We&amp;#x27;ll just say that the &lt;code&gt;type&lt;/code&gt; for clicking
the switch is &lt;code&gt;TOGGLE&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx" metastring="{6-7}"&gt;function Toggle() {
const [clicksSinceReset, setClicksSinceReset] = React.useState(0)
const tooManyClicks = clicksSinceReset &amp;gt;= 4
const {on, toggle, setOn, setOff} = useToggle({
reducer(currentState, action) {
if (tooManyClicks &amp;amp;&amp;amp; action.type === &amp;#x27;TOGGLE&amp;#x27;) {
// other changes are fine, but on needs to be unchanged
return {...action.changes, on: currentState.on}
} else {
// the changes are fine
return action.changes
}
},
})
function handleClick() {
toggle()
setClicksSinceReset(count =&amp;gt; count + 1)
}
return (
&amp;lt;div&amp;gt;
&amp;lt;button onClick={setOff}&amp;gt;Switch Off&amp;lt;/button&amp;gt;
&amp;lt;button onClick={setOn}&amp;gt;Switch On&amp;lt;/button&amp;gt;
&amp;lt;Switch on={on} onClick={handleClick} /&amp;gt;
{tooManyClicks ? (
&amp;lt;button onClick={() =&amp;gt; setClicksSinceReset(0)}&amp;gt;Reset&amp;lt;/button&amp;gt;
) : null}
&amp;lt;/div&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Nice! This gives us all kinds of control. One last thing, let&amp;#x27;s not bother with
the string &lt;code&gt;&amp;#x27;TOGGLE&amp;#x27;&lt;/code&gt; for the type. Instead we&amp;#x27;ll have an object of all the
change types that people can reference instead. This&amp;#x27;ll help avoid typos and
improve editor autocompletion:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx" metastring="{7}"&gt;function Toggle() {
const [clicksSinceReset, setClicksSinceReset] = React.useState(0)
const tooManyClicks = clicksSinceReset &amp;gt;= 4
const {on, toggle, setOn, setOff} = useToggle({
reducer(currentState, action) {
if (tooManyClicks &amp;amp;&amp;amp; action.type === useToggle.types.toggle) {
// other changes are fine, but on needs to be unchanged
return {...action.changes, on: currentState.on}
} else {
// the changes are fine
return action.changes
}
},
})
function handleClick() {
toggle()
setClicksSinceReset(count =&amp;gt; count + 1)
}
return (
&amp;lt;div&amp;gt;
&amp;lt;button onClick={setOff}&amp;gt;Switch Off&amp;lt;/button&amp;gt;
&amp;lt;button onClick={setOn}&amp;gt;Switch On&amp;lt;/button&amp;gt;
&amp;lt;Switch on={on} onClick={handleClick} /&amp;gt;
{tooManyClicks ? (
&amp;lt;button onClick={() =&amp;gt; setClicksSinceReset(0)}&amp;gt;Reset&amp;lt;/button&amp;gt;
) : null}
&amp;lt;/div&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Implementing a State Reducer with Hooks&lt;/h2&gt;&lt;p&gt;Alright, I&amp;#x27;m happy with the API we&amp;#x27;re exposing here. Let&amp;#x27;s take a look at how we
could implement this with our &lt;code&gt;useToggle&lt;/code&gt; hook. In case you forgot, here&amp;#x27;s the
code for that:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;function useToggle() {
const [on, setOnState] = React.useState(false)
const toggle = () =&amp;gt; setOnState(o =&amp;gt; !o)
const setOn = () =&amp;gt; setOnState(true)
const setOff = () =&amp;gt; setOnState(false)
return {on, toggle, setOn, setOff}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We &lt;em&gt;could&lt;/em&gt; add logic to every one of these helper functions, but I&amp;#x27;m just going
to skip ahead and tell you that this would be really annoying, even in this
simple hook. Instead, we&amp;#x27;re going to rewrite this from &lt;code&gt;useState&lt;/code&gt; to
&lt;code&gt;useReducer&lt;/code&gt; and that&amp;#x27;ll make our implementation a LOT easier:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;function toggleReducer(state, action) {
switch (action.type) {
case &amp;#x27;TOGGLE&amp;#x27;: {
return {on: !state.on}
}
case &amp;#x27;ON&amp;#x27;: {
return {on: true}
}
case &amp;#x27;OFF&amp;#x27;: {
return {on: false}
}
default: {
throw new Error(`Unhandled type: ${action.type}`)
}
}
}
function useToggle() {
const [{on}, dispatch] = React.useReducer(toggleReducer, {on: false})
const toggle = () =&amp;gt; dispatch({type: &amp;#x27;TOGGLE&amp;#x27;})
const setOn = () =&amp;gt; dispatch({type: &amp;#x27;ON&amp;#x27;})
const setOff = () =&amp;gt; dispatch({type: &amp;#x27;OFF&amp;#x27;})
return {on, toggle, setOn, setOff}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, cool. Really quick, let&amp;#x27;s add that &lt;code&gt;types&lt;/code&gt; property to our &lt;code&gt;useToggle&lt;/code&gt; to
avoid the strings thing:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx" metastring="{3,6,9,21-23,28-32}"&gt;function toggleReducer(state, action) {
switch (action.type) {
case useToggle.types.toggle: {
return {on: !state.on}
}
case useToggle.types.on: {
return {on: true}
}
case useToggle.types.off: {
return {on: false}
}
default: {
throw new Error(`Unhandled type: ${action.type}`)
}
}
}
function useToggle() {
const [{on}, dispatch] = React.useReducer(toggleReducer, {on: false})
const toggle = () =&amp;gt; dispatch({type: useToggle.types.toggle})
const setOn = () =&amp;gt; dispatch({type: useToggle.types.on})
const setOff = () =&amp;gt; dispatch({type: useToggle.types.off})
return {on, toggle, setOn, setOff}
}
useToggle.types = {
toggle: &amp;#x27;TOGGLE&amp;#x27;,
on: &amp;#x27;ON&amp;#x27;,
off: &amp;#x27;OFF&amp;#x27;,
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Cool, so now, users are going to pass &lt;code&gt;reducer&lt;/code&gt; as a configuration object to our
&lt;code&gt;useToggle&lt;/code&gt; function, so let&amp;#x27;s accept that:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx" metastring="{1}"&gt;function useToggle({reducer}) {
const [{on}, dispatch] = React.useReducer(toggleReducer, {on: false})
const toggle = () =&amp;gt; dispatch({type: useToggle.types.toggle})
const setOn = () =&amp;gt; dispatch({type: useToggle.types.on})
const setOff = () =&amp;gt; dispatch({type: useToggle.types.off})
return {on, toggle, setOn, setOff}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Great, so now that we have the developer&amp;#x27;s &lt;code&gt;reducer&lt;/code&gt;, how do we combine that
with our reducer? Well remember that the developer needs to know what our
changes will be, so we&amp;#x27;ll definitely need to determine those changes first.
Let&amp;#x27;s make an inline reducer:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx" metastring="{3-6}"&gt;function useToggle({reducer}) {
const [{on}, dispatch] = React.useReducer(
(state, action) =&amp;gt; {
const changes = toggleReducer(state, action)
return changes
},
{on: false},
)
const toggle = () =&amp;gt; dispatch({type: useToggle.types.toggle})
const setOn = () =&amp;gt; dispatch({type: useToggle.types.on})
const setOff = () =&amp;gt; dispatch({type: useToggle.types.off})
return {on, toggle, setOn, setOff}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That was a straight-up refactor. In fact, no functionality has changed for our
toggle hook (which is actually kinda neat if you think of it. The magic of black
boxes and implementation details ✨).&lt;/p&gt;&lt;p&gt;Awesome, so now we have all the info we need to pass along to the &lt;code&gt;reducer&lt;/code&gt;
they&amp;#x27;ve given to us:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx" metastring="{5}"&gt;function useToggle({reducer}) {
const [{on}, dispatch] = React.useReducer(
(state, action) =&amp;gt; {
const changes = toggleReducer(state, action)
return reducer(state, {...action, changes})
},
{on: false},
)
const toggle = () =&amp;gt; dispatch({type: useToggle.types.toggle})
const setOn = () =&amp;gt; dispatch({type: useToggle.types.on})
const setOff = () =&amp;gt; dispatch({type: useToggle.types.off})
return {on, toggle, setOn, setOff}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Cool! So we just call the developer&amp;#x27;s &lt;code&gt;reducer&lt;/code&gt; with the &lt;code&gt;state&lt;/code&gt; and make a new
&lt;code&gt;action&lt;/code&gt; object that has all the properties of the original &lt;code&gt;action&lt;/code&gt; plus the
&lt;code&gt;changes&lt;/code&gt;. Then we return whatever they return to us. And they have complete
control over our state updates! That&amp;#x27;s pretty neat! And thanks to &lt;code&gt;useReducer&lt;/code&gt;
it&amp;#x27;s pretty simple too.&lt;/p&gt;&lt;p&gt;But not everyone&amp;#x27;s going to need this &lt;code&gt;reducers&lt;/code&gt; feature, so let&amp;#x27;s default the
configuration object to &lt;code&gt;{}&lt;/code&gt; and we&amp;#x27;ll default the &lt;code&gt;reducer&lt;/code&gt; property to a
simple reducer that just always returns the changes:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx" metastring="{1}"&gt;function useToggle({reducer = (s, a) =&amp;gt; a.changes} = {}) {
const [{on}, dispatch] = React.useReducer(
(state, action) =&amp;gt; {
const changes = toggleReducer(state, action)
return reducer(state, {...action, changes})
},
{on: false},
)
const toggle = () =&amp;gt; dispatch({type: useToggle.types.toggle})
const setOn = () =&amp;gt; dispatch({type: useToggle.types.on})
const setOff = () =&amp;gt; dispatch({type: useToggle.types.off})
return {on, toggle, setOn, setOff}
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;Here&amp;#x27;s the final version:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;import React from &amp;#x27;react&amp;#x27;
import ReactDOM from &amp;#x27;react-dom&amp;#x27;
import Switch from &amp;#x27;./switch&amp;#x27;
function toggleReducer(state, action) {
switch (action.type) {
case useToggle.types.toggle: {
return {on: !state.on}
}
case useToggle.types.on: {
return {on: true}
}
case useToggle.types.off: {
return {on: false}
}
default: {
throw new Error(`Unhandled type: ${action.type}`)
}
}
}
function useToggle({reducer = (s, a) =&amp;gt; a.changes} = {}) {
const [{on}, dispatch] = React.useReducer(
(state, action) =&amp;gt; {
const changes = toggleReducer(state, action)
return reducer(state, {...action, changes})
},
{on: false},
)
const toggle = () =&amp;gt; dispatch({type: useToggle.types.toggle})
const setOn = () =&amp;gt; dispatch({type: useToggle.types.on})
const setOff = () =&amp;gt; dispatch({type: useToggle.types.off})
return {on, toggle, setOn, setOff}
}
useToggle.types = {
toggle: &amp;#x27;TOGGLE&amp;#x27;,
on: &amp;#x27;ON&amp;#x27;,
off: &amp;#x27;OFF&amp;#x27;,
}
function Toggle() {
const [clicksSinceReset, setClicksSinceReset] = React.useState(0)
const tooManyClicks = clicksSinceReset &amp;gt;= 4
const {on, toggle, setOn, setOff} = useToggle({
reducer(currentState, action) {
if (tooManyClicks &amp;amp;&amp;amp; action.type === useToggle.types.toggle) {
// other changes are fine, but on needs to be unchanged
return {...action.changes, on: currentState.on}
} else {
// the changes are fine
return action.changes
}
},
})
return (
&amp;lt;div&amp;gt;
&amp;lt;button onClick={setOff}&amp;gt;Switch Off&amp;lt;/button&amp;gt;
&amp;lt;button onClick={setOn}&amp;gt;Switch On&amp;lt;/button&amp;gt;
&amp;lt;Switch
onClick={() =&amp;gt; {
toggle()
setClicksSinceReset(count =&amp;gt; count + 1)
}}
on={on}
/&amp;gt;
{tooManyClicks ? (
&amp;lt;button onClick={() =&amp;gt; setClicksSinceReset(0)}&amp;gt;Reset&amp;lt;/button&amp;gt;
) : null}
&amp;lt;/div&amp;gt;
)
}
function App() {
return &amp;lt;Toggle /&amp;gt;
}
ReactDOM.render(&amp;lt;App /&amp;gt;, document.getElementById(&amp;#x27;root&amp;#x27;))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And here it is running in &lt;a href="https://codesandbox.io/s/9j0pkq30lo"&gt;a codesandbox&lt;/a&gt;:&lt;/p&gt;&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/9j0pkq30lo" style="width:100%;height:500px;border-width:0px;border-radius:4px;overflow:hidden"&gt;&lt;/iframe&gt;&lt;/p&gt;&lt;p&gt;Remember, what we&amp;#x27;ve done here is enable users to hook into every state update
of our reducer to make changes to it. This makes our hook WAY more flexible, but
it also means that the way we update state is now part of the API and if we make
changes to how that happens, then it could be a breaking change for users. It&amp;#x27;s
totally worth the trade-off for complex hooks/components, but it&amp;#x27;s just good to
keep that in mind.&lt;/p&gt;&lt;p&gt;I hope you find patterns like this useful. Thanks to &lt;code&gt;useReducer&lt;/code&gt;, this pattern
just kinda falls out (thank you React!). So give it a try on your codebase!&lt;/p&gt;&lt;p&gt;Good luck!&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/the-state-reducer-pattern-with-react-hooks"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Super simple start to serverless]]></title>
<description><![CDATA[This last little while I've been doing a fair amount of work on
kentcdodds.com . One page that I've been working on is
the contact page where you can
request enterprise training ,
schedule an hour of my time for consulting , or even
leave your…]]></description>
<link>https://kentcdodds.com/blog/super-simple-start-to-serverless</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/super-simple-start-to-serverless</guid>
<pubDate>Mon, 18 Mar 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;This last little while I&amp;#x27;ve been doing a fair amount of work on
&lt;a href="https://kentcdodds.com"&gt;kentcdodds.com&lt;/a&gt;. One page that I&amp;#x27;ve been working on is
the &lt;a href="https://kentcdodds.com/contact"&gt;contact page&lt;/a&gt; where you can
&lt;a href="https://kcd.im/request-a-workshop"&gt;request enterprise training&lt;/a&gt;,
&lt;a href="https://kcd.im/consulting"&gt;schedule an hour of my time for consulting&lt;/a&gt;, or even
&lt;a href="https://kcd.im/testimonial"&gt;leave your own testimonial of my work&lt;/a&gt; (I&amp;#x27;d love it
if you did!).&lt;/p&gt;&lt;p&gt;My app is built with &lt;a href="https://www.gatsbyjs.org"&gt;GatsbyJS&lt;/a&gt; which has quickly
become one of my favorite pieces of technology. Gatsby is a static site
generator, so it generates a bunch of HTML, CSS, and JavaScript files in a
directory called &lt;code&gt;public&lt;/code&gt; in my project and it leaves it to me to get those
files on the World Wide Web for you and your loved ones to enjoy.&lt;/p&gt;&lt;p&gt;So how do I get those files up there on the internet? I use
&lt;a href="https://www.netlify.com"&gt;Netlify&lt;/a&gt;! I&amp;#x27;ve LOVED Netlify for years. It&amp;#x27;s bonkers
how quickly I can get a site up and running (with HTTPS) with Netlify and it&amp;#x27;s
integration with GitHub is unmatched. I love it.&lt;/p&gt;&lt;p&gt;Great, so now I&amp;#x27;ve got static files served ultra-fast on the internet with
Netlify&amp;#x27;s CDN. But how do I make it so my contact form can actually send emails?
You may not be aware of this, but web browsers are not able to send emails
themselves. To do that you need a server. I don&amp;#x27;t know about you, but managing
servers and databases are among the top things on the list of stuff I do NOT
enjoy about web development.&lt;/p&gt;&lt;p&gt;You may have heard of &amp;quot;Serverless&amp;quot; or &amp;quot;Lambda Functions&amp;quot; or &amp;quot;Azure Functions&amp;quot;
etc. What&amp;#x27;s cool about this is you can write your server code without worrying
about managing servers or paying to have them sit around waiting for requests
all day long (which is particularly useful for a contact form like mine).&lt;/p&gt;&lt;p&gt;I remember years ago when those started getting popular, I tried them out a bit
and was reminded why I don&amp;#x27;t enjoy working with backend/devops stuff. As cool as
these functions were conceptually, I just didn&amp;#x27;t feel like I was smart enough to
navigate the complexities of the offerings.&lt;/p&gt;&lt;p&gt;Luckily for us, almost exactly one year ago from the time I&amp;#x27;m writing this,
Netlify took the complexity of AWS Lambda functions and made it super simple (I
think it&amp;#x27;s what they do best):&lt;/p&gt;&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;🚀Today we’re bringing &lt;a href="https://twitter.com/hashtag/serverless?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#serverless&lt;/a&gt; all the way to the frontend. Introducing AWS Lambda functions that deploy along with your site &lt;a href="https://t.co/UmbXOYWVH6"&gt;https://t.co/UmbXOYWVH6&lt;/a&gt; &lt;a href="https://t.co/9heC614qVs"&gt;pic.twitter.com/9heC614qVs&lt;/a&gt;&lt;/p&gt;— Netlify (@Netlify) &lt;a href="https://twitter.com/Netlify/status/976126036491386880"&gt;March 20, 2018&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;&lt;p&gt;I want to give you a really quick intro to using Netlify to deploy server code
in a way that is mind-blowingly straightforward to me.&lt;/p&gt;&lt;h2&gt;How to use Netlify Lambda Functions&lt;/h2&gt;&lt;p&gt;Before you get started, you&amp;#x27;ll need a &lt;a href="https://github.com"&gt;GitHub&lt;/a&gt; account, a
&lt;a href="https://netlify.com"&gt;Netlify&lt;/a&gt; account, and a fresh repository. Once you&amp;#x27;ve got
the project locally on your computer, then you can start with the following
steps:&lt;/p&gt;&lt;h3&gt;Step 1: Create a &lt;code&gt;netlify.toml&lt;/code&gt; file&lt;/h3&gt;&lt;p&gt;This file configures some stuff about our repository for netlify. Here&amp;#x27;s all you
need for this to work:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-toml"&gt;[build]
functions = &amp;quot;./functions&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;All this is saying is: Hey Netlify, when you build my project, the functions are
located in the &amp;quot;functions&amp;quot; directory.&lt;/p&gt;&lt;h3&gt;Step 2: Create &lt;code&gt;functions/hello.js&lt;/code&gt;&lt;/h3&gt;&lt;p&gt;Now that we&amp;#x27;ve told Netlify where to find our functions files, let&amp;#x27;s make one:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;// functions/hello.js
exports.handler = async event =&amp;gt; {
const subject = event.queryStringParameters.name || &amp;#x27;World&amp;#x27;
return {
statusCode: 200,
body: `Hello ${subject}!`,
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Netlify uses AWS Lambda under the hood, so you can checkout documentation and
learning materials about creating AWS Lambda functions for what kind of code can
go in there. We&amp;#x27;ll start with something simple that returns a promise (note it&amp;#x27;s
an &lt;code&gt;async&lt;/code&gt; function) which resolves to an object for the response we want for
this function. You can do all kinds of things in that function (like connect
with an SMTP mail server and send an email which is what I do in my contact
form).&lt;/p&gt;&lt;h3&gt;Step 3: Commit and push&lt;/h3&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1035px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/e9b1e11a5b8456e30563dd79e4daa55e/26bc0/code.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:71.39664804469274%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="The above code in an editor" title="The above code in an editor" src="https://kentcdodds.com/static/e9b1e11a5b8456e30563dd79e4daa55e/17fa4/code.png" srcSet="https://kentcdodds.com/static/e9b1e11a5b8456e30563dd79e4daa55e/f4a45/code.png 259w,https://kentcdodds.com/static/e9b1e11a5b8456e30563dd79e4daa55e/ef0f6/code.png 518w,https://kentcdodds.com/static/e9b1e11a5b8456e30563dd79e4daa55e/17fa4/code.png 1035w,https://kentcdodds.com/static/e9b1e11a5b8456e30563dd79e4daa55e/d6f0c/code.png 1553w,https://kentcdodds.com/static/e9b1e11a5b8456e30563dd79e4daa55e/26bc0/code.png 1790w" sizes="(max-width: 1035px) 100vw, 1035px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Now you can just do: &lt;code&gt;git add -A&lt;/code&gt;, then &lt;code&gt;git commit -m &amp;#x27;init&amp;#x27;&lt;/code&gt;, and
&lt;code&gt;git push -u origin master&lt;/code&gt; and you&amp;#x27;re set! Now let&amp;#x27;s go over to Netlify.&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1035px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/ccf05861e1dbb56b586f32bd7261ecaf/a6404/repo.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:40.20100502512563%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="The github repository" title="The github repository" src="https://kentcdodds.com/static/ccf05861e1dbb56b586f32bd7261ecaf/17fa4/repo.png" srcSet="https://kentcdodds.com/static/ccf05861e1dbb56b586f32bd7261ecaf/f4a45/repo.png 259w,https://kentcdodds.com/static/ccf05861e1dbb56b586f32bd7261ecaf/ef0f6/repo.png 518w,https://kentcdodds.com/static/ccf05861e1dbb56b586f32bd7261ecaf/17fa4/repo.png 1035w,https://kentcdodds.com/static/ccf05861e1dbb56b586f32bd7261ecaf/d6f0c/repo.png 1553w,https://kentcdodds.com/static/ccf05861e1dbb56b586f32bd7261ecaf/a6404/repo.png 1990w" sizes="(max-width: 1035px) 100vw, 1035px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;h3&gt;Step 4: Setup Netlify&lt;/h3&gt;&lt;p&gt;Go to &lt;a href="https://app.netlify.com"&gt;your netlify sites&lt;/a&gt; and click &amp;quot;New site from
Git.&amp;quot; From there you&amp;#x27;ll connect your Netlify account to your GitHub account and
it&amp;#x27;ll show you a list of repositories. Search for the one you want and click on
it.&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1035px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/02d9cba6a199ed7ccbb02707809b7d8f/e9603/create-new-site.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:122.63610315186246%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="Create New Site page" title="Create New Site page" src="https://kentcdodds.com/static/02d9cba6a199ed7ccbb02707809b7d8f/17fa4/create-new-site.png" srcSet="https://kentcdodds.com/static/02d9cba6a199ed7ccbb02707809b7d8f/f4a45/create-new-site.png 259w,https://kentcdodds.com/static/02d9cba6a199ed7ccbb02707809b7d8f/ef0f6/create-new-site.png 518w,https://kentcdodds.com/static/02d9cba6a199ed7ccbb02707809b7d8f/17fa4/create-new-site.png 1035w,https://kentcdodds.com/static/02d9cba6a199ed7ccbb02707809b7d8f/e9603/create-new-site.png 1396w" sizes="(max-width: 1035px) 100vw, 1035px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Go ahead and leave the &amp;quot;Build command&amp;quot; and &amp;quot;Publish directory&amp;quot; fields empty and
ignore the advanced options. Just click &amp;quot;Deploy site.&amp;quot;&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1035px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/c4b6281628dd131a659ca4ef905d6c37/0689a/overview.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:95.10344827586206%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="Overview page" title="Overview page" src="https://kentcdodds.com/static/c4b6281628dd131a659ca4ef905d6c37/17fa4/overview.png" srcSet="https://kentcdodds.com/static/c4b6281628dd131a659ca4ef905d6c37/f4a45/overview.png 259w,https://kentcdodds.com/static/c4b6281628dd131a659ca4ef905d6c37/ef0f6/overview.png 518w,https://kentcdodds.com/static/c4b6281628dd131a659ca4ef905d6c37/17fa4/overview.png 1035w,https://kentcdodds.com/static/c4b6281628dd131a659ca4ef905d6c37/d6f0c/overview.png 1553w,https://kentcdodds.com/static/c4b6281628dd131a659ca4ef905d6c37/a1bed/overview.png 2070w,https://kentcdodds.com/static/c4b6281628dd131a659ca4ef905d6c37/0689a/overview.png 2900w" sizes="(max-width: 1035px) 100vw, 1035px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Now you&amp;#x27;re on the Overview page of your site. It should only take a few seconds
to deploy your site. You can see info about that on the &amp;quot;Deploys&amp;quot; page. While
you wait, you can edit the Site name to be something more memorable by clicking
&amp;quot;Site settings.&amp;quot;&lt;/p&gt;&lt;p&gt;Once the deploy is finished, you can go to the &amp;quot;Functions&amp;quot; page:&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1035px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/c13684b6820a648abd6c20d9740c9e38/de157/functions.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:74.12008281573499%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="Functions page showing hello.js" title="Functions page showing hello.js" src="https://kentcdodds.com/static/c13684b6820a648abd6c20d9740c9e38/17fa4/functions.png" srcSet="https://kentcdodds.com/static/c13684b6820a648abd6c20d9740c9e38/f4a45/functions.png 259w,https://kentcdodds.com/static/c13684b6820a648abd6c20d9740c9e38/ef0f6/functions.png 518w,https://kentcdodds.com/static/c13684b6820a648abd6c20d9740c9e38/17fa4/functions.png 1035w,https://kentcdodds.com/static/c13684b6820a648abd6c20d9740c9e38/d6f0c/functions.png 1553w,https://kentcdodds.com/static/c13684b6820a648abd6c20d9740c9e38/a1bed/functions.png 2070w,https://kentcdodds.com/static/c13684b6820a648abd6c20d9740c9e38/de157/functions.png 2898w" sizes="(max-width: 1035px) 100vw, 1035px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;There you should see &lt;code&gt;hello.js&lt;/code&gt;! If you click that it&amp;#x27;ll show you the function
log. Calls from your function to &lt;code&gt;console.log&lt;/code&gt; should appear here with a
timestamp as well as a note for whenever your function is invoked:&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1035px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/b7bc63253c904e6a70bac9e67e9f2125/203a6/function-log.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:36.661211129296234%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="Function log page" title="Function log page" src="https://kentcdodds.com/static/b7bc63253c904e6a70bac9e67e9f2125/17fa4/function-log.png" srcSet="https://kentcdodds.com/static/b7bc63253c904e6a70bac9e67e9f2125/f4a45/function-log.png 259w,https://kentcdodds.com/static/b7bc63253c904e6a70bac9e67e9f2125/ef0f6/function-log.png 518w,https://kentcdodds.com/static/b7bc63253c904e6a70bac9e67e9f2125/17fa4/function-log.png 1035w,https://kentcdodds.com/static/b7bc63253c904e6a70bac9e67e9f2125/d6f0c/function-log.png 1553w,https://kentcdodds.com/static/b7bc63253c904e6a70bac9e67e9f2125/a1bed/function-log.png 2070w,https://kentcdodds.com/static/b7bc63253c904e6a70bac9e67e9f2125/203a6/function-log.png 2444w" sizes="(max-width: 1035px) 100vw, 1035px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Checkout the &amp;quot;Endpoint&amp;quot; and it shows your function is available on the World
Wide Web at &lt;code&gt;https://&amp;lt;your-site-name&amp;gt;.netlify.com/.netlify/functions/hello&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Really quick I just want to explain something. In &lt;code&gt;netlify.toml&lt;/code&gt; we told Netlify
that it can find the JavaScript for our functions in the &lt;code&gt;./functions&lt;/code&gt; directory
(we could&amp;#x27;ve called that whatever we wanted). Netlify takes each JavaScript file
in there and deploys it (as-is) to AWS lambda, then sets up an endpoint for
hitting that function for us under &lt;code&gt;/.netlify/functions&lt;/code&gt; (this is not
configurable AFAIK).&lt;/p&gt;&lt;p&gt;Cool, so now we can hit that URL and boom, Hello Bob Ross!&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1035px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/5ed5200a75528ced31143d6e12b4e39b/13bfc/function-output.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:44.04040404040405%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="Function output saying Hello Bob Ross" title="Function output saying Hello Bob Ross" src="https://kentcdodds.com/static/5ed5200a75528ced31143d6e12b4e39b/17fa4/function-output.png" srcSet="https://kentcdodds.com/static/5ed5200a75528ced31143d6e12b4e39b/f4a45/function-output.png 259w,https://kentcdodds.com/static/5ed5200a75528ced31143d6e12b4e39b/ef0f6/function-output.png 518w,https://kentcdodds.com/static/5ed5200a75528ced31143d6e12b4e39b/17fa4/function-output.png 1035w,https://kentcdodds.com/static/5ed5200a75528ced31143d6e12b4e39b/d6f0c/function-output.png 1553w,https://kentcdodds.com/static/5ed5200a75528ced31143d6e12b4e39b/13bfc/function-output.png 1980w" sizes="(max-width: 1035px) 100vw, 1035px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Wahoo!&lt;/p&gt;&lt;h2&gt;Next steps&lt;/h2&gt;&lt;p&gt;You can find my version of this project
&lt;a href="https://github.com/kentcdodds/super-simple-netlify-function-example"&gt;on GitHub&lt;/a&gt;
and
&lt;a href="https://simple-fn-example.netlify.com/.netlify/functions/hello"&gt;on Netlify&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;One important thing to note is that Netlify will send only the files for our
functions to AWS and no more. This means that if you try to &lt;code&gt;require&lt;/code&gt; something
from a local &lt;code&gt;utils&lt;/code&gt; directory or &lt;code&gt;node_modules&lt;/code&gt; you&amp;#x27;re out of luck.&lt;/p&gt;&lt;p&gt;Also, testing this locally is... not easy...&lt;/p&gt;&lt;p&gt;&lt;strong&gt;But wait!&lt;/strong&gt; Netlify engineers have built
&lt;a href="https://www.npmjs.com/package/netlify-lambda"&gt;&lt;code&gt;netlify-lambda&lt;/code&gt;&lt;/a&gt; to solve both
of these problems! I&amp;#x27;ve taken the liberty of giving you an example of this same
function that uses &lt;code&gt;netlify-lambda&lt;/code&gt; here
&lt;a href="https://github.com/kentcdodds/netlify-function-example"&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Here are the main changes:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Added a &lt;code&gt;package.json&lt;/code&gt; to configure npm/yarn to install &lt;code&gt;netlify-lambda&lt;/code&gt; and
created &lt;code&gt;dev&lt;/code&gt; and &lt;code&gt;build&lt;/code&gt; scripts.&lt;/li&gt;&lt;li&gt;Added a &lt;code&gt;.gitignore&lt;/code&gt; to ignore the &lt;code&gt;.netlify&lt;/code&gt; directory which is where
&lt;code&gt;netlify-lambda&lt;/code&gt; will place our compiled functions.&lt;/li&gt;&lt;li&gt;Added a &lt;code&gt;command&lt;/code&gt; line in our &lt;code&gt;netlify.toml&lt;/code&gt; file to have the build run the
command &lt;code&gt;npm run build&lt;/code&gt; which will trigger &lt;code&gt;netlify-lambda&lt;/code&gt; to build our
function into a single file for delivery to AWS Lambda.&lt;/li&gt;&lt;li&gt;Updated the &lt;code&gt;functions&lt;/code&gt; line in our &lt;code&gt;netlify.toml&lt;/code&gt; file to point to
&lt;code&gt;.netlify/functions/&lt;/code&gt; which is where &lt;code&gt;netlify-lambda&lt;/code&gt; will place our final
built functions.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Everything else is the same, but now we can actually require different files!&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;Any time we need to make a change to our function, we simply make those changes,
commit them to GitHub and Netlify will automatically update that on AWS Lambda.
It&amp;#x27;s very fast and super empowering.&lt;/p&gt;&lt;p&gt;I love enabling technologies like this. I shouldn&amp;#x27;t have to build an entire
backend with a database and server farm to allow you to send me
&lt;a href="https://kcd.im/request-a-workshop"&gt;Enterprise Training Inquiries&lt;/a&gt;, and thanks
to Netlify, I don&amp;#x27;t have to. It&amp;#x27;s pretty slick!&lt;/p&gt;&lt;p&gt;Give it a try! I think you&amp;#x27;ll love it too.&lt;/p&gt;&lt;h2&gt;P.S.&lt;/h2&gt;&lt;p&gt;My friend &lt;a href="https://twitter.com/swyx"&gt;Shawn Wang&lt;/a&gt; works at Netlify and he
mentioned he&amp;#x27;s working on a few neat things that he&amp;#x27;ll be announcing at
&lt;a href="https://twitter.com/jamstackconf"&gt;jamstackconf&lt;/a&gt; 2019. He gave me a discount
code you can use to get $100 off a ticket if you want to go: &lt;code&gt;friendsofswyx&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Also, Shawn mentioned that Netlify does have a Forms service built-in for
contact forms like I have. I originally used that, but it doesn&amp;#x27;t actually send
emails (you have to integrate with Zapier and it&amp;#x27;s an ok experience).&lt;/p&gt;&lt;p&gt;Also, while &lt;code&gt;/.netlify/functions&lt;/code&gt; is not configurable, you can alias it to
anything with a redirect, including serving your entire site from a function
which is pretty legit.&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/super-simple-start-to-serverless"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[How to get started with programming]]></title>
<description><![CDATA[Programming computers is amazing. There are so many things you can accomplish
with technology these days and being able to control what computers, phones, and
IoT devices do enables you
to accomplish so much more. There's no shortage of ideas of…]]></description>
<link>https://kentcdodds.com/blog/how-to-get-started-with-programming</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/how-to-get-started-with-programming</guid>
<pubDate>Wed, 06 Mar 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;Programming computers is amazing. There are so many things you can accomplish
with technology these days and being able to control what computers, phones, and
&lt;a href="https://en.wikipedia.org/wiki/Internet_of_things"&gt;IoT devices&lt;/a&gt; do enables you
to accomplish so much more.&lt;/p&gt;&lt;p&gt;There&amp;#x27;s no shortage of ideas of the things that we can accomplish with
technology. What&amp;#x27;s super cool about knowing how to program is the knowledge that
given enough time you can create your idea with technology yourself. Whether
that&amp;#x27;s &lt;a href="https://kentcdodds.com/blog/building-production-apps-100-in-the-browser"&gt;a simple todo app&lt;/a&gt;
with your specific requirements or the next Instagram, when you know how to
program, the possibilities are seemingly endless.&lt;/p&gt;&lt;p&gt;Now, let&amp;#x27;s not get ahead of ourselves. There&amp;#x27;s a reason that big tech companies
employ hundreds or even thousands of software programmers and it&amp;#x27;s because
building cool things like this is not easy. That said, there&amp;#x27;s so much good that
you can do with software, it&amp;#x27;s definitely worthwhile learning.&lt;/p&gt;&lt;h2&gt;So, where do I start?&lt;/h2&gt;&lt;p&gt;There is so much that you can do with programming these days that where you go
kinda depends on what you want to do with your coding skills. But regardless of
where you want to go with programming, there are some fundamental things you can
learn at the beginning to get your feet wet.&lt;/p&gt;&lt;p&gt;Whatever you end up doing to get started, I want to give you a suggestion:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Don&amp;#x27;t focus on learning to code. Focus on solving a problem that interests
you.&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;h2&gt;Learning Backwards&lt;/h2&gt;&lt;p&gt;I call this &lt;strong&gt;&amp;quot;learning backwards.&amp;quot;&lt;/strong&gt; By that I mean you start with what you
want to create, and learn the things you need to learn to accomplish your goals.
Doing things this way makes things much less abstract as you&amp;#x27;re learning a
subject that is all about abstraction.&lt;/p&gt;&lt;p&gt;However, doing this backward learning might be tough for you for a few reasons:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;You have so many ideas and you&amp;#x27;re not sure where to start.&lt;/li&gt;&lt;li&gt;Your ideas are so ambitious it&amp;#x27;s overwhelming.&lt;/li&gt;&lt;li&gt;You have no ideas at all. Everything&amp;#x27;s been done before.&lt;/li&gt;&lt;/ol&gt;&lt;h2&gt;Your first idea&lt;/h2&gt;&lt;p&gt;Here are some tips for combatting these issues. Just choose one idea and focus
on that one. The first program you write is going to have a LOT of problems. So
even if you do end up building a company out of this idea, it&amp;#x27;s unlikely that
what you sell to customers will resemble your first iteration even in the
slightest. So avoid thinking that the first thing you build is going to be a
life changing creation (I mean, learning programming could be life changing for
you, but it&amp;#x27;s unlikely to exist in it&amp;#x27;s initial form forever).&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Don&amp;#x27;t be afraid of making mistakes; instead embrace the fact that you will.
And do so with your eyes wide open.&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Also, don&amp;#x27;t stress over this first idea. It doesn&amp;#x27;t have to be a world shaking
idea. Here, let me give you a quick and easy way to come up with an idea. Think
of one of your hobbies. What&amp;#x27;s one repetitive task you find yourself doing
regularly with that hobby? Build a simple program that helps you do that
repetitive task so it takes less time.&lt;/p&gt;&lt;p&gt;Here&amp;#x27;s an example from my own life: I like playing board/card games and we have
lots of games like this, so we sometimes struggle deciding what to play. So I
could build a program that can help us decide which one to play by categorizing
our games and helps us decide by asking questions and then suggesting a few
options based on our answers.&lt;/p&gt;&lt;h2&gt;Now learn what you need to learn to build it&lt;/h2&gt;&lt;p&gt;Here&amp;#x27;s where things start to get a bit hard. Now that you have an idea of a
simple program that you want to build, you have a lot to learn. There are many
ways you can go about getting the information you need. In particular there are
many free resources available to learn the basics of programming.&lt;/p&gt;&lt;h3&gt;Foundational programming concepts&lt;/h3&gt;&lt;p&gt;One resource I suggest is &lt;a href="https://scratch.mit.edu"&gt;Scratch&lt;/a&gt; which is a
surprisingly powerful programming-like platform that doesn&amp;#x27;t require writing any
code at all. It&amp;#x27;s a great place to start learning about foundational programming
concepts like variables, loops, conditional statements, and events. You will
likely not even know that you&amp;#x27;re learning these things as you build stories and
games with the platform, but they will come to you and what you learn will help
you as you move onto the next phase of learning and getting your first idea
built.&lt;/p&gt;&lt;h3&gt;Writing a simple program&lt;/h3&gt;&lt;p&gt;Now you need to make a decision: what programming language do I use? Might I
suggest JavaScript. Not only because I&amp;#x27;ve bet the farm on JavaScript myself, but
also because of all programming languages it strikes the best balance of
approachability, ubiquity, and capability. JavaScript is by far the most
commonly used programming language in the world
(&lt;a href="https://insights.stackoverflow.com/survey/2018/#technology"&gt;Stack Overflow Survey 2018&lt;/a&gt;).
There are a lot of resources for the JavaScript language which can help you as
you start on the long journey of learning to code.&lt;/p&gt;&lt;p&gt;Having chosen JavaScript as your programming language I&amp;#x27;ll give you your first
opportunity to write some code now. You&amp;#x27;re probably reading this in an internet
browser like Chrome, Safari, Microsoft Edge, etc. Each of these run JavaScript
and are capable of running your JavaScript code! Go ahead and Google this: &amp;quot;How
to open the Developer Console in &lt;code&gt;&amp;lt;your browser&amp;gt;&lt;/code&gt;&amp;quot;&lt;/p&gt;&lt;p&gt;Here&amp;#x27;s what it looks like in Google Chrome on Mac:&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1035px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/f415ca6e870eb1a0754c5fc73556f8e7/b3a23/devtools-menu.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:31.24165554072096%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="developer tools menu" title="developer tools menu" src="https://kentcdodds.com/static/f415ca6e870eb1a0754c5fc73556f8e7/17fa4/devtools-menu.png" srcSet="https://kentcdodds.com/static/f415ca6e870eb1a0754c5fc73556f8e7/f4a45/devtools-menu.png 259w,https://kentcdodds.com/static/f415ca6e870eb1a0754c5fc73556f8e7/ef0f6/devtools-menu.png 518w,https://kentcdodds.com/static/f415ca6e870eb1a0754c5fc73556f8e7/17fa4/devtools-menu.png 1035w,https://kentcdodds.com/static/f415ca6e870eb1a0754c5fc73556f8e7/b3a23/devtools-menu.png 1498w" sizes="(max-width: 1035px) 100vw, 1035px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Clicking on that &amp;quot;Developer Tools&amp;quot; menu option opens up the Chrome Developer
Tools:&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1035px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/bc452034bfd1c852ddef76ced41fbac8/cc3b5/devtools.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:33.29864724245578%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="developer tools elements panel" title="developer tools elements panel" src="https://kentcdodds.com/static/bc452034bfd1c852ddef76ced41fbac8/17fa4/devtools.png" srcSet="https://kentcdodds.com/static/bc452034bfd1c852ddef76ced41fbac8/f4a45/devtools.png 259w,https://kentcdodds.com/static/bc452034bfd1c852ddef76ced41fbac8/ef0f6/devtools.png 518w,https://kentcdodds.com/static/bc452034bfd1c852ddef76ced41fbac8/17fa4/devtools.png 1035w,https://kentcdodds.com/static/bc452034bfd1c852ddef76ced41fbac8/d6f0c/devtools.png 1553w,https://kentcdodds.com/static/bc452034bfd1c852ddef76ced41fbac8/cc3b5/devtools.png 1922w" sizes="(max-width: 1035px) 100vw, 1035px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Now, what you want to bring up is the &amp;quot;Developer Console&amp;quot; which here is labeled
&amp;quot;Console.&amp;quot; If you click on that, it&amp;#x27;ll bring this up next:&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1035px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/3262d167370e98682d1fe4a76931eb12/13bfc/devtools-console.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:32.62626262626262%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="developer tools console panel" title="developer tools console panel" src="https://kentcdodds.com/static/3262d167370e98682d1fe4a76931eb12/17fa4/devtools-console.png" srcSet="https://kentcdodds.com/static/3262d167370e98682d1fe4a76931eb12/f4a45/devtools-console.png 259w,https://kentcdodds.com/static/3262d167370e98682d1fe4a76931eb12/ef0f6/devtools-console.png 518w,https://kentcdodds.com/static/3262d167370e98682d1fe4a76931eb12/17fa4/devtools-console.png 1035w,https://kentcdodds.com/static/3262d167370e98682d1fe4a76931eb12/d6f0c/devtools-console.png 1553w,https://kentcdodds.com/static/3262d167370e98682d1fe4a76931eb12/13bfc/devtools-console.png 1980w" sizes="(max-width: 1035px) 100vw, 1035px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;And this is your first window into programming in JavaScript! That area there is
where you can start typing out some code. Here, try typing &lt;code&gt;1 + 2&lt;/code&gt; and hit
&amp;quot;enter&amp;quot;&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:144px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/54352cecece35129a117493fa80ce2cd/b6dc4/1plus2.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:83.33333333333334%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="1 + 2 evaluating to 3" title="1 + 2 evaluating to 3" src="https://kentcdodds.com/static/54352cecece35129a117493fa80ce2cd/b6dc4/1plus2.png" srcSet="https://kentcdodds.com/static/54352cecece35129a117493fa80ce2cd/b6dc4/1plus2.png 144w" sizes="(max-width: 144px) 100vw, 144px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;There you go! You just wrote your first line of JavaScript. Of course, there&amp;#x27;s a
lot more to it than that, but that&amp;#x27;s a great place to start writing some simple
code.&lt;/p&gt;&lt;p&gt;One last thing before we move on (because this isn&amp;#x27;t really a tutorial), if you
want to save your work, you can do so by creating what&amp;#x27;s called an &amp;quot;HTML&amp;quot; file
that uses a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag in it. Go ahead and create a new file using a text
editor (like Notepad for Windows or TextEdit for macOS). Copy and paste this
into that file:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-html"&gt;&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;title&amp;gt;My first program&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;script&amp;gt;
function add(a, b) {
return a + b
}
const result = add(1, 2)
const message = &amp;#x27;The answer to 1 + 2 is&amp;#x27;
console.log(message, result)
&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;Note: make sure that you save it as a Plain Text file. To do this in TextEdit
click &amp;quot;Make Plain Text&amp;quot; under the &amp;quot;Format&amp;quot; menu before saving it.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Go ahead and save that file as &lt;code&gt;my-first-program.html&lt;/code&gt; onto your desktop. Then
open it up in your web browser and open the developer console on that page and
you should have something like this:&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1035px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/43659e20fc212c507ae137d72bc2a6fa/126c8/my-first-program.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:82.83828382838283%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="web page with something logged to the console" title="web page with something logged to the console" src="https://kentcdodds.com/static/43659e20fc212c507ae137d72bc2a6fa/17fa4/my-first-program.png" srcSet="https://kentcdodds.com/static/43659e20fc212c507ae137d72bc2a6fa/f4a45/my-first-program.png 259w,https://kentcdodds.com/static/43659e20fc212c507ae137d72bc2a6fa/ef0f6/my-first-program.png 518w,https://kentcdodds.com/static/43659e20fc212c507ae137d72bc2a6fa/17fa4/my-first-program.png 1035w,https://kentcdodds.com/static/43659e20fc212c507ae137d72bc2a6fa/126c8/my-first-program.png 1212w" sizes="(max-width: 1035px) 100vw, 1035px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Now you can play around in that file, make changes to it, and reload your page
and your program will run every time you do it. This is a great place to start
playing around with coding in JavaScript.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;I recommend that you install a real programming text editor like
&lt;a href="https://code.visualstudio.com"&gt;VSCode&lt;/a&gt;. It will really improve your
experience writing JavaScript programs.&lt;/p&gt;&lt;/blockquote&gt;&lt;h3&gt;Learning the JavaScript language&lt;/h3&gt;&lt;p&gt;After you&amp;#x27;ve become comfortable writing simple JavaScript code, it&amp;#x27;s time to
start learning the JavaScript language. There are a lot of resources for this
and you need to find something that matches your learning style. I recommend
googling around a little bit. You&amp;#x27;ll probably find some useful tutorials on
YouTube and there are lots of good books about JavaScript. One book that I can
suggest to you is the
&lt;a href="https://github.com/getify/You-Dont-Know-JS"&gt;You Don&amp;#x27;t Know JS&lt;/a&gt; book series.
It&amp;#x27;s pretty deep, but it&amp;#x27;ll give you a fantastic foundational understanding of
the language.&lt;/p&gt;&lt;p&gt;There&amp;#x27;s no shortcut to experience in coding I&amp;#x27;m afraid. So the more time you
spend actually writing code, the better you&amp;#x27;ll get at it. Keep at it! You can
totally do this.&lt;/p&gt;&lt;h2&gt;Now build your idea&lt;/h2&gt;&lt;p&gt;During this whole time, you should hopefully not have forgotten about the
original problem you wanted to solve. Once you&amp;#x27;ve written a few simple programs,
try to solve your problem with what you&amp;#x27;ve learned. What you build doesn&amp;#x27;t have
to look amazing, or work 100% of the time. You can work your way up to the
perfection you&amp;#x27;re hoping for. Build as simple of a version of what you&amp;#x27;re
looking for as possible.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;The process of success/failure is where you&amp;#x27;ll do the bulk of your learning,&lt;/strong&gt;
so don&amp;#x27;t feel bad if you&amp;#x27;re really struggling to learn this stuff. That&amp;#x27;s where
the real learning happens.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;I hope this is helpful to you. I&amp;#x27;m working on creating more resources for people
in your position myself, so I suggest you sign up for my newsletter here:
&lt;a href="https://kcd.im/news"&gt;kcd.im/news&lt;/a&gt;. Another tip for you is that in the software
industry, twitter is a pretty big platform where coders connect and communicate.
If you&amp;#x27;re not on twitter yet, jump on board and I have a suggestion for your
first follow: &lt;a href="https://twitter.com/kentcdodds"&gt;@kentcdodds&lt;/a&gt; 😉&lt;/p&gt;&lt;p&gt;Good luck to you!&lt;/p&gt;&lt;p&gt;P.S. If you&amp;#x27;d like to see more beginner material and tutorials from me, please
&lt;a href="https://twitter.com/intent/tweet?url=https%3A%2F%2Fkentcdodds.com%2Fblog%2Fhow-to-get-started-with-programming&amp;amp;text=Hey,%20@kentcdodds,%20I%27d%20love%20it%20if%20you%20could%20create%20more%20beginner%20programmer%20content!"&gt;ask me about it on twitter&lt;/a&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/how-to-get-started-with-programming"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[How to Enable React Strict Mode]]></title>
<description><![CDATA[In January 2018, Brian Vaughn
added <React.StrictMode /> .
Here's how to start using it in your app today: Ok, so what does this do? Go ahead and give it a try in your app and see what
happens. Don't worry, I'll wait... What happens will be…]]></description>
<link>https://kentcdodds.com/blog/react-strict-mode</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/react-strict-mode</guid>
<pubDate>Mon, 04 Mar 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;In January 2018, &lt;a href="https://twitter.com/brian_d_vaughn"&gt;Brian Vaughn&lt;/a&gt;
&lt;a href="https://github.com/facebook/react/pull/12083"&gt;added &lt;code&gt;&amp;lt;React.StrictMode /&amp;gt;&lt;/code&gt;&lt;/a&gt;.
Here&amp;#x27;s how to start using it in your app today:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-diff"&gt; ReactDOM.render(
- &amp;lt;App /&amp;gt;,
+ &amp;lt;React.StrictMode&amp;gt;&amp;lt;App /&amp;gt;&amp;lt;/React.StrictMode&amp;gt;
document.getElementById(&amp;#x27;root&amp;#x27;)
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, so what does this do? Go ahead and give it a try in your app and see what
happens. Don&amp;#x27;t worry, I&amp;#x27;ll wait...&lt;/p&gt;&lt;p&gt;&lt;img src="https://media.giphy.com/media/26gR1iYzSqtzcta4E/source.gif" alt="waiting..."/&gt;&lt;/p&gt;&lt;p&gt;What happens will be different for everyone, but here&amp;#x27;s an example of what some
of you might have seen:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Warning: A string ref, &amp;quot;myDiv&amp;quot;, has been found within a strict mode tree. String refs are a source of potential bugs and should be avoided. We recommend using createRef() instead.
in StringRef (created by App)
in StrictMode (created by App)
in App
Learn more about using refs safely here:
https://fb.me/react-strict-mode-string-ref
Warning: Unsafe lifecycle methods were found within a strict-mode tree:
in StrictMode (created by App)
in App
componentWillMount: Please update the following components to use componentDidMount instead: WillMount
componentWillReceiveProps: Please update the following components to use static getDerivedStateFromProps instead: WillReceiveProps
componentWillUpdate: Please update the following components to use componentDidUpdate instead: WillUpdate
Learn more about this warning here:
https://fb.me/react-strict-mode-warnings
Warning: Legacy context API has been detected within a strict-mode tree:
in StrictMode (created by App)
in App
Please update the following components: MyColorDiv, MyColorProvider
Learn more about this warning here:
https://fb.me/react-strict-mode-warnings
Warning: findDOMNode is deprecated in StrictMode. findDOMNode was passed an instance of FindDOMNode which is inside StrictMode. Instead, add a ref directly to the element you want to reference.
in div (created by FindDOMNode)
in FindDOMNode (created by App)
in StrictMode (created by App)
in App
Learn more about using refs safely here:
https://fb.me/react-strict-mode-find-node
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And here&amp;#x27;s the code that I used to generate those warnings:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;import React from &amp;#x27;react&amp;#x27;
import ReactDOM from &amp;#x27;react-dom&amp;#x27;
import PropTypes from &amp;#x27;prop-types&amp;#x27;
class WillMount extends React.Component {
componentWillMount() {
// Use componentDidMount instead
}
render() {
return null
}
}
class WillReceiveProps extends React.Component {
componentWillReceiveProps() {
// Use static getDerivedStateFromProps
}
render() {
return null
}
}
class WillUpdate extends React.Component {
componentWillUpdate() {
// Use componentDidUpdate instead
}
render() {
return null
}
}
class StringRef extends React.Component {
render() {
// Use React.createRef instead
return &amp;lt;div ref=&amp;quot;myDiv&amp;quot; /&amp;gt;
}
}
class FindDOMNode extends React.Component {
componentDidMount() {
// Use React.createRef instead
ReactDOM.findDOMNode(this)
}
render() {
return &amp;lt;div /&amp;gt;
}
}
class MyColorDiv extends React.Component {
// Use React.createContext().Consumer instead (or even better useContext)
static contextTypes = {color: PropTypes.string}
render() {
return &amp;lt;div style={{color: this.context.color}} /&amp;gt;
}
}
class MyColorProvider extends React.Component {
// Use React.createContext().Provider instead
static childContextTypes = {color: PropTypes.string}
getChildContext() {
return {color: &amp;#x27;purple&amp;#x27;}
}
render() {
return this.props.children
}
}
function App() {
return (
&amp;lt;&amp;gt;
&amp;lt;WillMount /&amp;gt;
&amp;lt;WillReceiveProps /&amp;gt;
&amp;lt;WillUpdate /&amp;gt;
&amp;lt;StringRef /&amp;gt;
&amp;lt;FindDOMNode /&amp;gt;
&amp;lt;MyColorProvider&amp;gt;
&amp;lt;MyColorDiv /&amp;gt;
&amp;lt;/MyColorProvider&amp;gt;
&amp;lt;/&amp;gt;
)
}
ReactDOM.render(
&amp;lt;React.StrictMode&amp;gt;
&amp;lt;App /&amp;gt;
&amp;lt;/React.StrictMode&amp;gt;,
document.getElementById(&amp;#x27;root&amp;#x27;),
)
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;And you can check this out for yourself in
&lt;a href="https://codesandbox.io/s/y01q7vmpnz"&gt;this codesandbox&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Each of these warnings has a solid workaround that will make your code better in
various ways (most of them are related to concurrent mode which should hopefully
come to React later this year). Getting these warnings taken care of today will
make it much easier for you to upgrade to concurrent react bug-free when it
comes along.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;That said, don&amp;#x27;t freak out if you have a ton of warnings in your app. Your
code will continue to work in the future. There&amp;#x27;s also an &lt;code&gt;UNSAFE_&lt;/code&gt; prefix for
those lifecycle methods you can use to silence the warning if you need. React
wont leave you in the dust here.&lt;/p&gt;&lt;/blockquote&gt;&lt;h2&gt;It runs code TWICE&lt;/h2&gt;&lt;p&gt;Another thing that React Strict Mode does is run certain callbacks/methods twice
(in DEV mode ONLY). You read that right! The following callbacks/methods will be
run twice in Strict Mode (in DEV mode ONLY):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Class component &lt;code&gt;constructor&lt;/code&gt; method&lt;/li&gt;&lt;li&gt;The &lt;code&gt;render&lt;/code&gt; method (includes function components)&lt;/li&gt;&lt;li&gt;&lt;code&gt;setState&lt;/code&gt; updater functions (the first argument)&lt;/li&gt;&lt;li&gt;The static &lt;code&gt;getDerivedStateFromProps&lt;/code&gt; lifecycle&lt;/li&gt;&lt;li&gt;The &lt;code&gt;React.useState&lt;/code&gt; state initializer callback function&lt;/li&gt;&lt;li&gt;The &lt;code&gt;React.useMemo&lt;/code&gt; callback&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;Checkout &lt;a href="https://codesandbox.io/s/xvv55893mp"&gt;this codesandbox&lt;/a&gt; which logs to
the console in hook callbacks and class methods to show you that certain
things happen twice.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;React does this because it cannot reliably warn you against side-effects you do
in those methods. But if those methods are idempotent, then calling them
multiple times shouldn&amp;#x27;t cause any trouble. If they are not idempotent, then you
should notice funny things which you should hopefully be able to notice and fix.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Note that &lt;code&gt;useEffect&lt;/code&gt; and &lt;code&gt;useLayoutEffect&lt;/code&gt; callbacks are &lt;em&gt;not&lt;/em&gt; called twice
even in dev mode + strict mode because the entire point of those callbacks
&lt;em&gt;is&lt;/em&gt; to perform side-effects.&lt;/p&gt;&lt;p&gt;Note that I also observed that the &lt;code&gt;reducer&lt;/code&gt; you pass to &lt;code&gt;React.useReducer&lt;/code&gt; is
&lt;em&gt;not&lt;/em&gt; called twice in dev mode. I&amp;#x27;m not sure why this is because I feel like
that could also benefit from this kind of warning.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;You&amp;#x27;ll note that if you download either of my codesandbox projects and run the
&lt;code&gt;build&lt;/code&gt; script (which enables production mode), all of the warnings go away and
the callbacks are only called once. This is because these are only there to help
you during development and will not impact you in production.&lt;/p&gt;&lt;h2&gt;Third Party Code&lt;/h2&gt;&lt;p&gt;Rendering your app in &lt;code&gt;React.StrictMode&lt;/code&gt; will warn you when a component is using
a suboptimal method or API and it will help you catch things that can cause bugs
that can be hard to debug. But sometimes the code that&amp;#x27;s violating strict mode
isn&amp;#x27;t your own code, but code in a library.&lt;/p&gt;&lt;p&gt;So what do you do when you get a warning like this in a third-party component? I
recommend seeing how easy it would be to
&lt;a href="http://makeapullrequest.com"&gt;open a PR&lt;/a&gt; to the project. If that doesn&amp;#x27;t work
out, then you could just &amp;quot;vendor&amp;quot; (download and commit it) or &amp;quot;fork&amp;quot; that
dependency and move on.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;Remember, &lt;strong&gt;your code will continue to work&lt;/strong&gt; whether you&amp;#x27;re using strict mode
and fixing the warnings or not.&lt;/p&gt;&lt;p&gt;One approach that I think many teams are adopting (and I recommend) is to start
by wrapping parts of your app in &lt;code&gt;&amp;lt;React.StrictMode /&amp;gt;&lt;/code&gt; instead of the entire
app:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;function App() {
return (
&amp;lt;div&amp;gt;
&amp;lt;OldPartOfTheApp /&amp;gt;
&amp;lt;React.StrictMode&amp;gt;
&amp;lt;SomeNewFeature /&amp;gt;
&amp;lt;/React.StrictMode&amp;gt;
&amp;lt;AnotherOlderPartOfTheApp /&amp;gt;
&amp;lt;/div&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can use &lt;code&gt;&amp;lt;React.StrictMode /&amp;gt;&lt;/code&gt; anywhere in your app at any depth. This can
be great way to opt certain parts of your app into strict mode without getting a
ton of warnings everywhere.&lt;/p&gt;&lt;p&gt;I hope that doing this will help you catch bugs in your React codebases!&lt;/p&gt;&lt;p&gt;See you around 💯&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Read more about Strict Mode from
&lt;a href="https://reactjs.org/docs/strict-mode.html"&gt;the react docs&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/react-strict-mode"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Goodbye Medium]]></title>
<description><![CDATA[I've been a blogger for over 15 years. When I was a teenager, I had a blog on
blogger all about what Google was working on. I was one of the first bloggers to
report on Google's acquisition of YouTube (my blog got an insane number of views
that day…]]></description>
<link>https://kentcdodds.com/blog/goodbye-medium</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/goodbye-medium</guid>
<pubDate>Mon, 25 Feb 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;I&amp;#x27;ve been a blogger for over 15 years. When I was a teenager, I had a blog on
blogger all about what Google was working on. I was one of the first bloggers to
report on Google&amp;#x27;s acquisition of YouTube (my blog got an insane number of views
that day).&lt;/p&gt;&lt;p&gt;I also used to write (on blogger) one called &amp;quot;Google Video Highlights&amp;quot; where I
and some random stranger I &amp;quot;met&amp;quot; on the internet would take turns posting random
videos that we found on Google Video (Google&amp;#x27;s answer to YouTube before they
just bought YouTube).&lt;/p&gt;&lt;p&gt;I&amp;#x27;ve had many blogs on many platforms since then: Blogger, wordpress.org, custom
wordpress, ghost, Jekyll, and finally Medium.com.&lt;/p&gt;&lt;p&gt;For me, blogging is all about convenience. I&amp;#x27;ve always been more motivated to
create content than create a blogging platform, so I always looked for the
easiest way to do that. That said, I did want to differentiate myself (which is
why I tried wordpress). Every time I tried, I was reminded that building a
blogging platform was distracting me from creating content (not that building a
platform isn&amp;#x27;t a great way to learn, it just wasn&amp;#x27;t what I wanted to learn).&lt;/p&gt;&lt;p&gt;So when Medium became a thing years ago, I made the decision to go all in on
Medium. I was really happy with the authoring experience. It really removed
friction for me.&lt;/p&gt;&lt;p&gt;I started out on Medium at &lt;code&gt;medium.com/@kentcdodds&lt;/code&gt;, but after a while, I
realized that I didn&amp;#x27;t trust Medium to be around forever or (more likely) that I
would want to be on Medium forever. I knew it was inevitable that eventually
Medium would do some things with my content that I didn&amp;#x27;t like. So about a year
or two ago I decided to create a &amp;quot;kentcdodds&amp;quot; publication and I used a (now
unsupported) feature of Medium to host my custom publication at a custom domain:
&lt;code&gt;blog.kentcdodds.com&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;I started publishing blog posts every week, and over 100 blog posts later, I
finally decided that the &amp;quot;cost&amp;quot; of creating my own blog platform was worth the
effort. Links to my articles on &lt;code&gt;blog.kentcdodds.com&lt;/code&gt; have been shared with
millions of people all over the world on platforms like Twitter, Reddit, &amp;quot;the
orange site,&amp;quot; and on other platforms. Because I own the domain, &lt;strong&gt;I was able to
make this move without worrying about all those links breaking!&lt;/strong&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Note: this is actually the same reason I use &lt;code&gt;kcd.im&lt;/code&gt; so much as well. I can
change where those URLs go if I ever need to which I definitely have. I
recommend
&lt;a href="https://youtu.be/HL6paXyx6hM?index=40&amp;amp;list=PLV5CVI1eNcJgCrPH_e6d57KRUTiDZgs0u"&gt;you set up a URL shortener yourself&lt;/a&gt;
(it&amp;#x27;ll take you minutes and it&amp;#x27;s totally free).&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I spent 1 hour building
&lt;a href="https://github.com/kentcdodds/kcd-blog-redirector"&gt;&lt;code&gt;kcd-blog-redirector&lt;/code&gt;&lt;/a&gt;. I
even livestreamed it on my new &amp;quot;Coding with Kent&amp;quot; series:&lt;/p&gt;&lt;p&gt;&lt;iframe width="100%" height="315" src="https://www.youtube-nocookie.com/embed/1EOj__JPN08?rel=0&amp;amp;list=PLV5CVI1eNcJgJCEkMlsqXea6OIF_uV_ub" frameBorder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""&gt;&lt;/iframe&gt;&lt;/p&gt;&lt;p&gt;(You might think this would be a simple task, but it&amp;#x27;s more complicated than you
think. Watch the first few minutes of the video and you&amp;#x27;ll know what I mean.)&lt;/p&gt;&lt;p&gt;I spent MANY more hours working on kentcdodds.com and preparing
kentcdodds.com/blog. In the last few weeks, I&amp;#x27;ve spent many hours working on
migrating all my old Medium posts from blog.kentcdodds.com to
kentcdodds.com/blog. (You can watch those on
&lt;a href="https://kcd.im/coding"&gt;&amp;quot;Coding with Kent&amp;quot;&lt;/a&gt; as well).&lt;/p&gt;&lt;h2&gt;Why leave Medium?&lt;/h2&gt;&lt;p&gt;So... What did Medium do that made it worth leaving? Well,
&lt;a href="https://medium.com/@dan_abramov/why-my-new-blog-isnt-on-medium-3b280282fbae"&gt;Dan Abramov described it pretty well here&lt;/a&gt;.
To sum up:&lt;/p&gt;&lt;blockquote&gt;&lt;ol&gt;&lt;li&gt;Some of my Medium articles unexpectedly got behind a paywall (this doesn&amp;#x27;t
actually happen, but it&amp;#x27;s an understandable misunderstanding 🤔)&lt;/li&gt;&lt;li&gt;My views on some topics have changed. (I also took the opportunity to leave
behind some old posts that aren&amp;#x27;t really applicable to me anymore).&lt;/li&gt;&lt;li&gt;I want to dogfood React. (This is a fantastic place for me to play around
with React in a safe environment where it&amp;#x27;s not a huge deal if I break
stuff).&lt;/li&gt;&lt;li&gt;I like to have full control over the experience. (This is a big one for
me!)&lt;/li&gt;&lt;li&gt;It’s open to the collaboration. (My blog is open source and every article
has a link where you can contribute fixes!)&lt;/li&gt;&lt;/ol&gt;&lt;/blockquote&gt;&lt;p&gt;I think one of the biggest things that bugs me about Medium is this:&lt;/p&gt;&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;Wait, why did I come to this site again? &lt;a href="https://t.co/9rHce97Nvu"&gt;pic.twitter.com/9rHce97Nvu&lt;/a&gt;&lt;/p&gt;— Nicholas C. Zakas (@slicknet) &lt;a href="https://twitter.com/slicknet/status/1097584328962240512"&gt;February 18, 2019&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;&lt;p&gt;This is CRAZY. Like, what? I definitely want control over how my content is
consumed.&lt;/p&gt;&lt;h2&gt;So what now?&lt;/h2&gt;&lt;p&gt;The blog has several things that I need to work on still:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="https://github.com/kentcdodds/kentcdodds.com/issues/48"&gt;Search&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/kentcdodds/kentcdodds.com/issues/49"&gt;Category Pages&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/kentcdodds/kentcdodds.com/issues/50"&gt;Keyword Pages&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/kentcdodds/kentcdodds.com/issues/51"&gt;Fix the RSS Feed&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Figure out how to automate sending emails that include nice syntax
highlighting&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;There&amp;#x27;s a lot more (no, I&amp;#x27;m not planning on adding comments, we can chat on
twitter). What&amp;#x27;s cool is that with amazing tools like Gatsby, I feel empowered
to build this stuff without sinking crazy amounts of time into it and building a
mess.&lt;/p&gt;&lt;h2&gt;How can I help?&lt;/h2&gt;&lt;p&gt;I&amp;#x27;m so glad you asked! I know for a fact that some of the articles didn&amp;#x27;t import
very well. The import process from Medium to Markdown is... imperfect (actually
it&amp;#x27;s downright terrible), so there are some issues with some of the markdown.&lt;/p&gt;&lt;p&gt;If you&amp;#x27;d like to help, I&amp;#x27;d love your help making sure things look ok and if they
don&amp;#x27;t fixing them.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;So if you&amp;#x27;d like to help,&lt;/strong&gt; I invite you to
&lt;a href="https://docs.google.com/spreadsheets/d/1Fro-0x305nDsnoYuhid4qJRgcDb1a7-uXTvAU6EEa3U/edit?usp=sharing"&gt;join us on this Google Doc here&lt;/a&gt;
and checkout the old Medium Post and compare it to the Imported post. Then fill
out the &amp;quot;Looks good?&amp;quot; column with either Yes, No Issue(s) Reported, or Pull
Request(s) Created. (There&amp;#x27;s even a link for editing the post yourself if you
want!)&lt;/p&gt;&lt;p&gt;I&amp;#x27;m looking forward to working on this further and I&amp;#x27;m also really looking
forward to some of the content that I&amp;#x27;m going to be bringing you to egghead.io
and... other places :)&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Stuff not to miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://thinkster.io/tutorials/one-day-introduction-to-react-with-kent-c-dodds"&gt;One Day Introduction to React with Kent C. Dodds&lt;/a&gt;:
This is a recorded workshop from back in October. If you&amp;#x27;re totally new to
React and want a hands-on approach to learning it, this will be very helpful
to you! (There&amp;#x27;s also
&lt;a href="https://www.google.com/url?q=https://thinkster.io/pro/yearly/kcd-react-workshop"&gt;a HUGE sale right now on thinkster&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;&lt;a href="https://ti.to/thinkster-io/react-hooks-workshop-slc-may-2019"&gt;I&amp;#x27;M GIVING A HOOKS WORKSHOP IN SALT LAKE CITY!!!!!&lt;/a&gt;:
Both beginner and advanced. Check it out!&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/goodbye-medium"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[React Hooks: Compound Components]]></title>
<description><![CDATA[A few weeks ago I did a DevTips with Kent livestream
where I show you how to refactor the compound components pattern from a class
component to a function component with React hooks: https://youtu.be/415EfGPuhSo?list=PLV5CVI1eNcJgCrPH_e6d…]]></description>
<link>https://kentcdodds.com/blog/compound-components-with-react-hooks</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/compound-components-with-react-hooks</guid>
<pubDate>Mon, 18 Feb 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;A few weeks ago I did a &lt;a href="https://kcd.im/devtips"&gt;DevTips with Kent&lt;/a&gt; livestream
where I show you how to refactor the compound components pattern from a class
component to a function component with React hooks:&lt;/p&gt;&lt;p&gt;&lt;iframe width="100%" height="315" src="https://www.youtube-nocookie.com/embed/415EfGPuhSo?rel=0&amp;amp;list=PLV5CVI1eNcJgCrPH_e6d57KRUTiDZgs0u" frameBorder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""&gt;&lt;/iframe&gt;&lt;/p&gt;&lt;p&gt;If you&amp;#x27;re unfamiliar with compound components, then you probably haven&amp;#x27;t watched
my Advanced React Component Patterns course
&lt;a href="http://kcd.im/advanced-react"&gt;on egghead.io&lt;/a&gt; or
&lt;a href="https://frontendmasters.com/courses/advanced-react-patterns"&gt;on Frontend Masters&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;The idea is that you have two or more components that work together to
accomplish a useful task. Typically one component is the parent, and the other
is the child. The objective is to provide a more expressive and flexible API.&lt;/p&gt;&lt;p&gt;Think of it like &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;option&amp;gt;&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-html"&gt;&amp;lt;select&amp;gt;
&amp;lt;option value=&amp;quot;value1&amp;quot;&amp;gt;key1&amp;lt;/option&amp;gt;
&amp;lt;option value=&amp;quot;value2&amp;quot;&amp;gt;key2&amp;lt;/option&amp;gt;
&amp;lt;option value=&amp;quot;value3&amp;quot;&amp;gt;key3&amp;lt;/option&amp;gt;
&amp;lt;/select&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you were to try and use one without the other it wouldn&amp;#x27;t work (or make
sense). Additionally it&amp;#x27;s actually a really great API. Let&amp;#x27;s check out what it
would look like if we didn&amp;#x27;t have a compound components API to work with
(remember, this is HTML, not JSX):&lt;/p&gt;&lt;pre&gt;&lt;code class="language-html"&gt;&amp;lt;select options=&amp;quot;key1:value1;key2:value2;key3:value3&amp;quot;&amp;gt;&amp;lt;/select&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I&amp;#x27;m sure you can think of other ways to express this, but yuck. And how would
you express the &lt;code&gt;disabled&lt;/code&gt; attribute with this kind of API? It&amp;#x27;s kinda madness.&lt;/p&gt;&lt;p&gt;So the compound components API gives you a nice way to express relationships
between components.&lt;/p&gt;&lt;p&gt;Another important aspect of this is the concept of &amp;quot;implicit state.&amp;quot; The
&lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt; element implicitly stores state about the selected option and shares
that with it&amp;#x27;s children so they know how to render themselves based on that
state. But that state sharing is implicit because there&amp;#x27;s nothing in our HTML
code that can even access the state (and it doesn&amp;#x27;t need to anyway).&lt;/p&gt;&lt;p&gt;Alright, let&amp;#x27;s get a look at a legit React component that exposes a compound
component to understand these principles further. Here&amp;#x27;s an example of
&lt;a href="https://ui.reach.tech/menu-button"&gt;the &lt;code&gt;&amp;lt;Menu /&amp;gt;&lt;/code&gt; component from Reach UI&lt;/a&gt; that
exposes a compound components API:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;function App() {
return (
&amp;lt;Menu&amp;gt;
&amp;lt;MenuButton&amp;gt;
Actions &amp;lt;span aria-hidden&amp;gt;▾&amp;lt;/span&amp;gt;
&amp;lt;/MenuButton&amp;gt;
&amp;lt;MenuList&amp;gt;
&amp;lt;MenuItem onSelect={() =&amp;gt; alert(&amp;#x27;Download&amp;#x27;)}&amp;gt;Download&amp;lt;/MenuItem&amp;gt;
&amp;lt;MenuItem onSelect={() =&amp;gt; alert(&amp;#x27;Copy&amp;#x27;)}&amp;gt;Create a Copy&amp;lt;/MenuItem&amp;gt;
&amp;lt;MenuItem onSelect={() =&amp;gt; alert(&amp;#x27;Delete&amp;#x27;)}&amp;gt;Delete&amp;lt;/MenuItem&amp;gt;
&amp;lt;/MenuList&amp;gt;
&amp;lt;/Menu&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In this example, the &lt;code&gt;&amp;lt;Menu&amp;gt;&lt;/code&gt; establishes some shared implicit state. The
&lt;code&gt;&amp;lt;MenuButton&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;MenuList&amp;gt;&lt;/code&gt;, and &lt;code&gt;&amp;lt;MenuItem&amp;gt;&lt;/code&gt; components each access and/or
manipulate that state, and it&amp;#x27;s all done implicitly. This allows you to have the
expressive API you&amp;#x27;re looking for.&lt;/p&gt;&lt;p&gt;So how is this done? Well, if you watch
&lt;a href="https://kcd.im/advanced-react"&gt;my course&lt;/a&gt; I show you two ways to do it. One
with &lt;code&gt;React.cloneElement&lt;/code&gt; on the children and the other with React context. (My
course will need to be slightly updated to show how to do this with hooks). In
this blog post, I&amp;#x27;ll show you how to create a simple set of compound components
using context.&lt;/p&gt;&lt;p&gt;When teaching a new concept, I prefer to use simple examples at first. So we&amp;#x27;ll
use my favorite &lt;code&gt;&amp;lt;Toggle&amp;gt;&lt;/code&gt; component example for this.&lt;/p&gt;&lt;p&gt;Here&amp;#x27;s how our &lt;code&gt;&amp;lt;Toggle&amp;gt;&lt;/code&gt; compound components are going to be used:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;function App() {
return (
&amp;lt;Toggle onToggle={on =&amp;gt; console.log(on)}&amp;gt;
&amp;lt;Toggle.On&amp;gt;The button is on&amp;lt;/Toggle.On&amp;gt;
&amp;lt;Toggle.Off&amp;gt;The button is off&amp;lt;/Toggle.Off&amp;gt;
&amp;lt;Toggle.Button /&amp;gt;
&amp;lt;/Toggle&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You&amp;#x27;ll notice that we&amp;#x27;re using a &lt;code&gt;.&lt;/code&gt; in our component names. That&amp;#x27;s because
those components are added as static properties to the &lt;code&gt;&amp;lt;Toggle&amp;gt;&lt;/code&gt; component.
Note that this is not at all a requirement of compound components (the &lt;code&gt;&amp;lt;Menu&amp;gt;&lt;/code&gt;
components above do not do this). I just like doing this as a way to explicitly
communicate the relationship.&lt;/p&gt;&lt;p&gt;Ok, the moment you&amp;#x27;ve all been waiting for, the actual full implementation of
compound components with context and hooks:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;import React from &amp;#x27;react&amp;#x27;
// this switch implements a checkbox input and is not relevant for this example
import {Switch} from &amp;#x27;../switch&amp;#x27;
const ToggleContext = React.createContext()
function useEffectAfterMount(cb, dependencies) {
const justMounted = React.useRef(true)
React.useEffect(() =&amp;gt; {
if (!justMounted.current) {
return cb()
}
justMounted.current = false
}, dependencies)
}
function Toggle(props) {
const [on, setOn] = React.useState(false)
const toggle = React.useCallback(() =&amp;gt; setOn(oldOn =&amp;gt; !oldOn), [])
useEffectAfterMount(() =&amp;gt; {
props.onToggle(on)
}, [on])
const value = React.useMemo(() =&amp;gt; ({on, toggle}), [on])
return (
&amp;lt;ToggleContext.Provider value={value}&amp;gt;
{props.children}
&amp;lt;/ToggleContext.Provider&amp;gt;
)
}
function useToggleContext() {
const context = React.useContext(ToggleContext)
if (!context) {
throw new Error(
`Toggle compound components cannot be rendered outside the Toggle component`,
)
}
return context
}
function On({children}) {
const {on} = useToggleContext()
return on ? children : null
}
function Off({children}) {
const {on} = useToggleContext()
return on ? null : children
}
function Button(props) {
const {on, toggle} = useToggleContext()
return &amp;lt;Switch on={on} onClick={toggle} {...props} /&amp;gt;
}
// for convenience, but totally not required...
Toggle.On = On
Toggle.Off = Off
Toggle.Button = Button
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here&amp;#x27;s this component in action:&lt;/p&gt;&lt;iframe src="https://codesandbox.io/embed/9yp5p2z7yr" style="width:100%;height:500px;border-width:0px;border-radius:4px;overflow:hidden" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"&gt;&lt;/iframe&gt;&lt;p&gt;So the way this works is we create a context with React where we store the state
and a mechanism for updating the state. Then the &lt;code&gt;&amp;lt;Toggle&amp;gt;&lt;/code&gt; component is
responsible for providing that context value to the rest of the react tree.&lt;/p&gt;&lt;p&gt;I&amp;#x27;ll walkthrough this implementation and explain the particulars in a future
update to my Advanced React Component Patterns course. So keep an eye out for
that!&lt;/p&gt;&lt;p&gt;I hope that helps you get some ideas of ways you can make your component APIs
more expressive and useful. Good luck!&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/compound-components-with-react-hooks"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[🚨 Big Announcement: I'm a full-time educator! 👨‍🏫]]></title>
<description><![CDATA[I've been teaching for as long as I can remember. I talk about this a lot in
"Why and How I started public speaking" ,
but just know that I have a love of teaching, I've done it a lot, and I want to
do more. This is why I'm excited to announce that…]]></description>
<link>https://kentcdodds.com/blog/full-time-educator</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/full-time-educator</guid>
<pubDate>Sun, 17 Feb 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;I&amp;#x27;ve been teaching for as long as I can remember. I talk about this a lot in
&lt;a href="https://kentcdodds.com/blog/why-and-how-i-started-public-speaking"&gt;&amp;quot;Why and How I started public speaking&amp;quot;&lt;/a&gt;,
but just know that I have a love of teaching, I&amp;#x27;ve done it a lot, and I want to
do more. &lt;strong&gt;This is why I&amp;#x27;m excited to announce that I&amp;#x27;ve gone full-time
educator!&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;What does this mean? Well, it means that I&amp;#x27;ll be able to spend my daytime
completely focused on making content that will &lt;strong&gt;help you level up your skills
as a developer&lt;/strong&gt;. And it means that I can spend my nighttime with my wife and
kids (not that I wasn&amp;#x27;t, but when I&amp;#x27;ve worked on big things like
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt; my wife didn&amp;#x27;t see much
of me in the evenings).&lt;/p&gt;&lt;p&gt;So what am I working on? Here are a few things I&amp;#x27;m planning:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Remote workshops. Lots of remote workshops. Stay tuned for more info on how
to sign up for those :)&lt;/li&gt;&lt;li&gt;More sites like &lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;. Stuff
for React, JavaScript, HTML, CSS, and more more more!&lt;/li&gt;&lt;li&gt;Quality improvements to &lt;a href="https://kcd.im/devtips"&gt;DevTips with Kent&lt;/a&gt;
livestreams!&lt;/li&gt;&lt;li&gt;Some time to write and publish my fantasy novels:
&lt;a href="https://kcd.im/shurlan"&gt;Shurlan&lt;/a&gt; ⚪&lt;/li&gt;&lt;li&gt;More &lt;a href="https://kcd.im/egghead"&gt;egghead.io&lt;/a&gt; and
&lt;a href="https://kcd.im/fem"&gt;Frontend Masters&lt;/a&gt; courses!&lt;/li&gt;&lt;li&gt;Improved curation of the mountain of content I&amp;#x27;ve put together over the
years, making it easier for you to pull value out of the stuff I&amp;#x27;m creating.&lt;/li&gt;&lt;li&gt;Quality improvements to this newsletter, my website, and blog. Also making it
easier to get value from that stuff.&lt;/li&gt;&lt;li&gt;There&amp;#x27;s more... But I&amp;#x27;m going to surprise you 😜&lt;/li&gt;&lt;/ol&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;I had amazing experiences and co-workers at PayPal. I built some things that I&amp;#x27;m
really proud of while there. If you&amp;#x27;re looking for a place to work, I highly
recommend you &lt;a href="http://paypal.jobs"&gt;give PayPal a close look&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;I can&amp;#x27;t wait to show you what I have in store for you. Just to get things going,
I made this egghead.io lesson today! Give it a watch 💯&lt;/p&gt;&lt;p&gt;&lt;a href="https://egghead.io/lessons/react-detect-user-activity-with-a-custom-useidle-react-hook?pl=react-hooks-and-suspense-650307f2"&gt;&lt;strong&gt;Detect user activity with a custom useIdle React Hook&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1035px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/ddd951f4a736a738df4aa48f25cb51c1/a1bed/use-idle.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:62.512077294685994%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="useIdle egghead lesson screenshot" title="useIdle egghead lesson screenshot" src="https://kentcdodds.com/static/ddd951f4a736a738df4aa48f25cb51c1/17fa4/use-idle.png" srcSet="https://kentcdodds.com/static/ddd951f4a736a738df4aa48f25cb51c1/f4a45/use-idle.png 259w,https://kentcdodds.com/static/ddd951f4a736a738df4aa48f25cb51c1/ef0f6/use-idle.png 518w,https://kentcdodds.com/static/ddd951f4a736a738df4aa48f25cb51c1/17fa4/use-idle.png 1035w,https://kentcdodds.com/static/ddd951f4a736a738df4aa48f25cb51c1/d6f0c/use-idle.png 1553w,https://kentcdodds.com/static/ddd951f4a736a738df4aa48f25cb51c1/a1bed/use-idle.png 2070w" sizes="(max-width: 1035px) 100vw, 1035px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Good luck, and stay tuned!&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/full-time-educator"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Should I useState or useReducer?]]></title>
<description><![CDATA[Whenever there are two things to do the same thing, people inevitably ask: "When
do I use one over the other?" For example
"When do I use useEffect and useLayoutEffect ?"
Or
"When do I use Unit, Integration, or E2E tests?"
Or
"When to use…]]></description>
<link>https://kentcdodds.com/blog/should-i-usestate-or-usereducer</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/should-i-usestate-or-usereducer</guid>
<pubDate>Mon, 11 Feb 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;Whenever there are two things to do the same thing, people inevitably ask: &amp;quot;When
do I use one over the other?&amp;quot;&lt;/p&gt;&lt;p&gt;For example
&lt;a href="https://kentcdodds.com/blog/useeffect-vs-uselayouteffect"&gt;&amp;quot;When do I use &lt;code&gt;useEffect&lt;/code&gt; and &lt;code&gt;useLayoutEffect&lt;/code&gt;?&amp;quot;&lt;/a&gt;
Or
&lt;a href="https://kentcdodds.com/blog/unit-vs-integration-vs-e2e-tests"&gt;&amp;quot;When do I use Unit, Integration, or E2E tests?&amp;quot;&lt;/a&gt;
Or
&lt;a href="https://kentcdodds.com/blog/control-props-vs-state-reducers"&gt;&amp;quot;When to use Control Props or State Reducers?&amp;quot;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I think &lt;code&gt;useState&lt;/code&gt; and &lt;code&gt;useReducer&lt;/code&gt; are no exception to this at all. In fact,
&lt;a href="https://twitter.com/immatthamlin"&gt;Matt Hamlin&lt;/a&gt; already posted
&lt;a href="https://matthamlin.me/blog/2019/february/why-you-should-useReducer"&gt;useReducer, don&amp;#x27;t useState&lt;/a&gt;
and he makes some great points there. I&amp;#x27;d like to throw my hat in this
discussion though because
&lt;a href="https://github.com/kentcdodds/ama/issues/587"&gt;I was asked about it on my AMA&lt;/a&gt;.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Congratulations on the new design of your website kentcdodds.com. Looking at
the source code of your website, in the
&lt;a href="https://github.com/kentcdodds/kentcdodds.com/blob/ed55aea3a58d24813a59cf72d8ffbdfbd96f769e/src/components/Forms/Subscribe.js"&gt;&lt;code&gt;Subscribe&lt;/code&gt;&lt;/a&gt;
component, you used useState hooks to handle the state of this component. My
question is, is not it more optimized to use a useReducer here instead of
several useState? If not, why?&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Here&amp;#x27;s the top of that Subscribe component&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;const [submitted, setSubmitted] = React.useState(false)
const [loading, setLoading] = React.useState(false)
const [response, setResponse] = React.useState(null)
const [errorMessage, setErrorMessage] = React.useState(null)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then there&amp;#x27;s logic throughout the component for calling those state updater
functions with the appropriate data, like here:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;async function handleSubmit(values) {
setSubmitted(false)
setLoading(true)
try {
const responseJson = await fetch(/* stuff */).then(r =&amp;gt; r.json())
setSubmitted(true)
setResponse(responseJson)
setErrorMessage(null)
} catch (error) {
setSubmitted(false)
setErrorMessage(&amp;#x27;Something went wrong!&amp;#x27;)
}
setLoading(false)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If I were to rewrite this to use &lt;code&gt;useReducer&lt;/code&gt; then it would look like this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;const [state, dispatch] = React.useReducer(reducer, {
submitted: false,
loading: false,
response: null,
errorMessage: null,
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then the &lt;code&gt;reducer&lt;/code&gt; would look something like this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;const types = {
SUBMIT_STARTED: 0,
}
function reducer(state, action) {
switch (action.type) {
case types.SUBMIT_STARTED: {
return {...state, submitted: false, loading: true}
}
case types.SUBMIT_COMPLETE: {
return {
...state,
submitted: true,
response: action.response,
errorMessage: null,
loading: false,
}
}
case types.SUBMIT_ERROR: {
return {
...state,
submitted: false,
errorMessage: action.errorMessage,
loading: false,
}
}
default: {
return state
}
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And the &lt;code&gt;handleSubmit&lt;/code&gt; function would look like this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;async function handleSubmit(values) {
dispatch({type: types.SUBMIT_STARTED})
try {
const responseJson = await fetch(/* stuff */).then(r =&amp;gt; r.json())
dispatch({type: types.SUBMIT_COMPLETE, response: responseJson})
} catch (error) {
dispatch({type: types.SUBMIT_ERROR, errorMessage: &amp;#x27;Something went wrong!&amp;#x27;})
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Matt Hamlin brings up in his blog post a few benefits to &lt;code&gt;useReducer&lt;/code&gt; over
&lt;code&gt;useState&lt;/code&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Easier to manage larger state shapes&lt;/li&gt;&lt;li&gt;Easier to reason about by other developers&lt;/li&gt;&lt;li&gt;Easier to test&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;For this specific case I don&amp;#x27;t think that the first or second point really
applies. Four elements of state is hardly a &amp;quot;large state shape&amp;quot; and the
before/after here is no easier or harder to &amp;quot;reason about&amp;quot; for me. I think
they&amp;#x27;re equally simple/complex.&lt;/p&gt;&lt;p&gt;As for testing, I would definitely agree that you could test the &lt;code&gt;reducer&lt;/code&gt; in
isolation and that could be a nice benefit if I were doing a bunch of business
logic in there, but I&amp;#x27;m not really. It&amp;#x27;s pretty simple there.&lt;/p&gt;&lt;p&gt;Typically I prefer to write higher-level integration-like tests, so I wouldn&amp;#x27;t
want to write tests for that &lt;code&gt;reducer&lt;/code&gt; in isolation and instead would test the
&lt;code&gt;&amp;lt;Subscribe /&amp;gt;&lt;/code&gt; component and my tests would treat the reducer as an
implementation detail.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Now if there were some complex business logic in that &lt;code&gt;reducer&lt;/code&gt; or several
edge cases, then I definitely would want to test that in isolation (and I
would use &lt;a href="https://github.com/atlassian/jest-in-case"&gt;&lt;code&gt;jest-in-case&lt;/code&gt;&lt;/a&gt; to do
it!).&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I think there is one main situation in which I prefer &lt;code&gt;useState&lt;/code&gt; over
&lt;code&gt;useReducer&lt;/code&gt;:&lt;/p&gt;&lt;p&gt;&lt;strong&gt;When prototyping/building the component and you&amp;#x27;re not certain of the
implementation&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;While building a new component, you&amp;#x27;re often adding/removing state from that
component&amp;#x27;s implementation. I think it would be harder to do that if you do this
with a reducer. Once you solidified what you want your component to look like
then you can go make the decision of whether converting from several &lt;code&gt;useState&lt;/code&gt;s
to a &lt;code&gt;useReducer&lt;/code&gt; makes sense. Additionally, maybe you&amp;#x27;ll decide that
&lt;code&gt;useReducer&lt;/code&gt; makes sense for some of it and a custom hook that uses &lt;code&gt;useState&lt;/code&gt;
would make sense for other parts of your component logic. I find it&amp;#x27;s almost
always better to wait until I know what my code is going to look like before I
start making abstractions.&lt;/p&gt;&lt;p&gt;Oh, and if you&amp;#x27;re prototyping, the code can be as unmaintainable as you want :)
So who cares? Do what&amp;#x27;s faster.&lt;/p&gt;&lt;h2&gt;One situation when &lt;code&gt;useReducer&lt;/code&gt; is basically always better&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;If your one element of your state relies on the value of another element of
your state, then it&amp;#x27;s almost always best to use &lt;code&gt;useReducer&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;For example, imagine you have a tic-tac-toe game you&amp;#x27;re writing. You have one
element of state called &lt;code&gt;squares&lt;/code&gt; which is just an array of all the squares and
their value:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;[
&amp;#x27; &amp;#x27;, &amp;#x27;X&amp;#x27;, &amp;#x27;O&amp;#x27;,
&amp;#x27;X&amp;#x27;, &amp;#x27;O&amp;#x27;, &amp;#x27;X&amp;#x27;,
&amp;#x27; &amp;#x27;, &amp;#x27; &amp;#x27;, &amp;#x27;X&amp;#x27;
]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;and another called &lt;code&gt;xIsNext&lt;/code&gt; which maintains the who&amp;#x27;s turn it is. When a user
clicks on a square, how does your code know whether the &lt;code&gt;squares&lt;/code&gt; array should
update to &lt;code&gt;X&lt;/code&gt; or &lt;code&gt;O&lt;/code&gt;? It determines this based on the &lt;code&gt;xIsNext&lt;/code&gt; state. Because
of this, it&amp;#x27;s easier to use a reducer because the reducer function can accept
all of the current state and use that current state (which includes &lt;code&gt;xIsNext&lt;/code&gt;)
to determine the new state.&lt;/p&gt;&lt;p&gt;The benefits here are &lt;em&gt;mostly&lt;/em&gt; just code aesthetic, but if you start adding
async behavior here, then the case for &lt;code&gt;useReducer&lt;/code&gt; is even more strong. With
our tic-tac-toe game, you can reference the current value of &lt;code&gt;xIsNext&lt;/code&gt; in the
closure, but if you are updating the &lt;code&gt;squares&lt;/code&gt; state asynchronously, then you
could be working with stale values of state which may or may not be what you
want. Using a reducer completely removes this potential issue though, which is
why I say it&amp;#x27;s basically always better to use a reducer if your state elements
depend on one another when they&amp;#x27;re updated.&lt;/p&gt;&lt;p&gt;Here&amp;#x27;s an example of tic-tac-toe with &lt;code&gt;useReducer&lt;/code&gt;:&lt;/p&gt;&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/r1m6pz58mq" style="width:100%;height:500px;border-width:0px;border-radius:4px;overflow:hidden"&gt;&lt;/iframe&gt;&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;So what&amp;#x27;s the answer? Really, it depends. &lt;code&gt;useState&lt;/code&gt; is literally built on top
of &lt;code&gt;useReducer&lt;/code&gt;. I don&amp;#x27;t think there are any relevant performance concerns
between the two so it&amp;#x27;s mostly a cosmetic/preferential decision.&lt;/p&gt;&lt;p&gt;While I conceptually like what Matt is encouraging, I think I may have a longer
threshold before I&amp;#x27;ll reach for &lt;code&gt;useReducer&lt;/code&gt; to replace my &lt;code&gt;useState&lt;/code&gt;. I also
really appreciate Matt for including this:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;they both have benefits and fallbacks that depend entirely upon their use&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I think the best thing you can do to develop an intuition for when to reach for
one or the other is to feel the pain. Use them both and see how happy/sad they
make your life.&lt;/p&gt;&lt;p&gt;Good luck!&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/should-i-usestate-or-usereducer"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Intentional Career Building]]></title>
<description><![CDATA[I've been thinking a lot about this newsletter and what I want to do with it.
One thing I want to do is provide you with some specific ideas of things you can
do to improve your skills and get what you want out of your career. So today I'm
going to…]]></description>
<link>https://kentcdodds.com/blog/intentional-career-building</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/intentional-career-building</guid>
<pubDate>Mon, 11 Feb 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;I&amp;#x27;ve been thinking a lot about this newsletter and what I want to do with it.
One thing I want to do is provide you with some specific ideas of things you can
do to improve your skills and get what you want out of your career. So today I&amp;#x27;m
going to give you a few ideas of things you can do to be more intentional about
building your career (or *gasp* &amp;quot;personal brand&amp;quot;).&lt;/p&gt;&lt;p&gt;I didn&amp;#x27;t start out intentionally seeking/tracking followers, but over time I
learned a few things that could gain me a wider reach. I realized that by
intentionally building upon my career and my personal brand I felt like I had
more job security. After building enough of a following, I&amp;#x27;m much less worried
about what would happen if I were to suddenly be let go from my job. I could
just send you all and email and send out a tweet and because I&amp;#x27;ve developed a
following of you good people who seem to think I know what I&amp;#x27;m doing 1) people
would see it and 2) people would care. It also makes me feel more confident that
I don&amp;#x27;t have to do a job that I would rather not do and I can have the
flexibility to choose between multiple great options. This is a great position
for a husband and father of four to be in.&lt;/p&gt;&lt;p&gt;So here are a few things that I&amp;#x27;ve done that have worked out pretty well for me
and I think could be reproducible for many of you.&lt;/p&gt;&lt;h2&gt;Communicate&lt;/h2&gt;&lt;p&gt;Whether you&amp;#x27;re building your clout inside your company or outside, communicating
your accomplishments is really important. You may have saved the company from
financial ruin by fixing that critical bug last night, but if nobody knows the
scope of what you did or even that you&amp;#x27;re the one who did it then you&amp;#x27;re not
going to receive the credit. You don&amp;#x27;t have to be all cocky about it (that&amp;#x27;s
pretty annoying), and if you weren&amp;#x27;t the only one who helped make something
happen make sure you give credit where it&amp;#x27;s due. At the end of the day, make
sure that people understand the value that you&amp;#x27;re creating.&lt;/p&gt;&lt;h2&gt;Double dip&lt;/h2&gt;&lt;p&gt;I&amp;#x27;m not talking about getting paid for the same work by two different companies
(that is probably a really bad idea and illegal I&amp;#x27;m guessing). What I am saying
is that if someone at work asks you a question about testing a react component,
then maybe you can share your answer in a public gist on GitHub and send it to
your co-worker as well as twitter. Just an idea there. I do this ALL. THE. TIME.&lt;/p&gt;&lt;h2&gt;Create value, not spam&lt;/h2&gt;&lt;p&gt;I get questions about getting noticed and recognized a lot.
&lt;a href="https://twitter.com/gulshansainis/status/1085854812694929408"&gt;This tweet thread in particular is very helpful in this regard&lt;/a&gt;.
Remember that it takes a very long time to get noticed and when you only have a
few dozen followers on twitter or other platforms your awesome content can never
seem to get to the right places. But I can tell you that even when someone
shares awesome content with me, I&amp;#x27;m less likely to look at it if I can tell
they&amp;#x27;ve been spamming it out to everyone they can think of or they bug me about
it a lot.&lt;/p&gt;&lt;p&gt;Respect people and their time. They may not always be able to help you or give
your stuff the time of day. But be patient and keep creating things that are
solving real problems &lt;em&gt;YOU&lt;/em&gt; are experiencing, and eventually that will resonate
with enough people that they don&amp;#x27;t want to miss your next big value add.&lt;/p&gt;&lt;h2&gt;Own your content&lt;/h2&gt;&lt;p&gt;If you&amp;#x27;re publishing to a domain you don&amp;#x27;t control, then you should consider
making a change. I was luckily grandfathered into Medium&amp;#x27;s custom domain thing
before they stopped doing that which is why my medium blog is at
&lt;code&gt;blog.kentcdodds.com&lt;/code&gt; rather than &lt;code&gt;medium.com/@kentcdodds&lt;/code&gt;. I am planning on
moving off of medium soon (UPDATE, I did:
&lt;a href="https://kentcdodds.com/blog/goodbye-medium"&gt;Goodbye Medium&lt;/a&gt;) and when I do I&amp;#x27;ll easily be able to
redirect all my blog posts to my new custom platform because I own the domain
name that all the links on twitter and elsewhere are pointing to.&lt;/p&gt;&lt;p&gt;This is also why I care so much about having
&lt;a href="https://youtu.be/HL6paXyx6hM?list=PLV5CVI1eNcJgCrPH_e6d57KRUTiDZgs0u"&gt;a URL shortener&lt;/a&gt;.
When I switched from tinyletter.com to buttondown.email and then to
convertkit.com, I was able to simply update &lt;code&gt;kcd.im/news&lt;/code&gt; to point to the new
sign-up page and all existing links started taking people to the right place.&lt;/p&gt;&lt;p&gt;Owning the domain and sharing links to domains that you own can be very
powerful.&lt;/p&gt;&lt;h2&gt;Timing&lt;/h2&gt;&lt;p&gt;This is very anecdotal, but I&amp;#x27;ve found that the time of day/week that you share
your content can have an impact on who sees it. Consider that nobody&amp;#x27;s looking
at twitter on Friday evenings and people often don&amp;#x27;t look at articles over the
weekends (there&amp;#x27;s a reason most newsletters are sent during the week days). I
typically try to announce my stuff earlier in the week and often in the morning
before many people in the US really get to working and before many people on the
other side of the pacific go to sleep.&lt;/p&gt;&lt;h2&gt;Consistency&lt;/h2&gt;&lt;p&gt;People often need to see your avatar associated with useful content multiple
times before they realize that they like what you&amp;#x27;re producing. So pushing out
consistent useful stuff on multiple platforms is really helpful. As a part of
this, using a consistent name and avatar (that actually looks like you if
possible... I realize this is a luxury that some people do not have due to
terrible stalker situations 🙁) across platforms that you rarely change (mine
has been the same for... a long time) can really help people recognize who you
are and associate your content with you on each of those platforms. Also, having
a consistent username across those platforms is also helpful.&lt;/p&gt;&lt;p&gt;Another note about consistency is to consider the message you&amp;#x27;re trying to
communicate to your audience and stick to that message as much as you can. Maybe
leave the cat and baby pictures for other platforms or accounts (I realize that
nobody&amp;#x27;s a mono-dimensional person and we should embrace our multi-dimensional
selves, but this is just something that I&amp;#x27;ve noticed has an affect on my
effectiveness at reaching people so I thought I&amp;#x27;d mention it).&lt;/p&gt;&lt;p&gt;As an example, I&amp;#x27;ve recently gotten into writing a novel. I&amp;#x27;ve tweeted about it
a lot. I decided that I&amp;#x27;m going to get more serious about this novel writing
stuff and will probably be tweeting about it more, so I created
&lt;a href="https://twitter.com/kent_writes"&gt;a new twitter account @kent_writes for the purpose&lt;/a&gt;.&lt;/p&gt;&lt;h2&gt;Solve real problems &lt;em&gt;you&lt;/em&gt; are having&lt;/h2&gt;&lt;p&gt;This one carries with it the assumption that you actually have problems which
don&amp;#x27;t already have solutions. The npm ecosystem is full of solutions and you can
probably find solutions to many use cases already. Don&amp;#x27;t bother spending a lot
of time building the next &amp;quot;redux simplifier&amp;quot; package because there are a million
of those out there and frankly I don&amp;#x27;t personally find them interesting at all.
And don&amp;#x27;t invent problems just so you can create solutions to them. Nobody will
care. Contribute to existing solutions, and solve problems where there are no
solutions or the existing solutions are lacking.&lt;/p&gt;&lt;h2&gt;Be patient&lt;/h2&gt;&lt;p&gt;Building your career clout/personal brand is important and takes a lot of time.
Be patient and humble. Lift others up and help people in your own way.
Eventually you will get recognized for it. I&amp;#x27;m not saying you wont fall prey to
our societies natural and unfortunately biases. Many people have to deal with
those on a regular basis and it&amp;#x27;s totally not fair. Keep working at it though
and you will find success.&lt;/p&gt;&lt;p&gt;I hope that&amp;#x27;s helpful to you. Good luck.&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;&lt;strong&gt;Call to action&lt;/strong&gt;:&lt;/p&gt;&lt;p&gt;Choose one of the following things to do this week to be intentional about
building your career:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Write the blog post you wish existed last week when you were learning
something new&lt;/li&gt;&lt;li&gt;Answer your co-worker&amp;#x27;s question in a public space (YouTube, gist, etc.) and
share it&lt;/li&gt;&lt;li&gt;Write an email to your higher-ups describing the role you and your team mates
played in a recently completed project. Tell them you just want to share
something you were proud of and that you love working at a place where you can
tackle such challenges.&lt;/li&gt;&lt;li&gt;Go for a walk (sometimes you just need to take care of yourself and think)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://dev.to/lkopacz/4-things-that-i-always-manually-test-2je8"&gt;4 things that I always manually test&lt;/a&gt;
and
&lt;a href="https://dev.to/lkopacz/a11y-and-js---a-seemingly-unconventional-romance-24i0"&gt;a11y and JS - A Seemingly Unconventional Romance&lt;/a&gt;
both by &lt;a href="https://twitter.com/littlekope0903"&gt;Lindsey Kopacz&lt;/a&gt; are both terrific
articles about accessibility I recommend you read.&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;a href="https://twitter.com/kentcdodds/status/1095101380631584769"&gt;Share and participate in the discussion on twitter&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/intentional-career-building"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Please stop building inaccessible forms (and how to fix them)]]></title>
<description><![CDATA[Note, today's blog post is very heavily inspired by the
Labeling Controls tutorial
from w3.org . HTML is accessible by default. This is true, with the important caveat that
when you use semantic HTML properly, what you've built will be accessible…]]></description>
<link>https://kentcdodds.com/blog/please-stop-building-inaccessible-forms-and-how-to-fix-them</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/please-stop-building-inaccessible-forms-and-how-to-fix-them</guid>
<pubDate>Mon, 04 Feb 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;blockquote&gt;&lt;p&gt;Note, today&amp;#x27;s blog post is very heavily inspired by the
&lt;a href="https://www.w3.org/WAI/tutorials/forms/labels"&gt;Labeling Controls tutorial&lt;/a&gt;
from &lt;a href="https://www.w3.org"&gt;w3.org&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;strong&gt;HTML is accessible by default.&lt;/strong&gt; This is true, with the important caveat that
when you use semantic HTML properly, what you&amp;#x27;ve built will be accessible. Now,
there are lots of ways that you can mess this up. Today I&amp;#x27;m going to focus on
&lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; and how to ensure that your form controls (inputs) are properly
labeled.&lt;/p&gt;&lt;p&gt;Before I get into that, allow me to just take a quick tangent and say this:
PLEASE USE YOUR FORM WITH NOTHING BUT THE KEYBOARD AND SEE IF IT IS POSSIBLE. So
many forms are impossible to use without a mouse and it drives me crazy. Lucky
for me I &lt;em&gt;can&lt;/em&gt; use a mouse, but so many people in the world cannot. For them, it
is impossible to fill out your form.&lt;/p&gt;&lt;p&gt;Ok, so let&amp;#x27;s talk about labels.&lt;/p&gt;&lt;p&gt;I&amp;#x27;m regularly confronted with a form control that&amp;#x27;s written like this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-html"&gt;Username: &amp;lt;input /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To a seeing user, this looks fine, but to a blind user, they&amp;#x27;ll need to use a
screen reader and without a label the user is left to their best guess as to
what the input is expecting when they focus on the input.&lt;/p&gt;&lt;p&gt;But it takes more than just putting the label text in a &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; input. So this
wont work:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-html"&gt;&amp;lt;label&amp;gt;Username&amp;lt;/label&amp;gt; &amp;lt;input /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;⚡️ You can know that the input has a label associated with it by checking the
input&amp;#x27;s &lt;code&gt;labels&lt;/code&gt; property or the label&amp;#x27;s &lt;code&gt;control&lt;/code&gt; property.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Ok, here are four ways to associate the label with the input (in order of
personal preference):&lt;/p&gt;&lt;h2&gt;label[for] ➡ input[id]&lt;/h2&gt;&lt;pre&gt;&lt;code class="language-html"&gt;&amp;lt;label for=&amp;quot;username&amp;quot;&amp;gt;Username&amp;lt;/label&amp;gt; &amp;lt;input id=&amp;quot;username&amp;quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;input[aria-labeledby] ➡ label[id]&lt;/h2&gt;&lt;pre&gt;&lt;code class="language-html"&gt;&amp;lt;label id=&amp;quot;username&amp;quot;&amp;gt;Username&amp;lt;/label&amp;gt; &amp;lt;input aria-labeledby=&amp;quot;username&amp;quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;label 🤗 input&lt;/h2&gt;&lt;blockquote&gt;&lt;p&gt;I like to think of this one as the label hugging the input&lt;/p&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code class="language-html"&gt;&amp;lt;label&amp;gt;
Username
&amp;lt;input /&amp;gt;
&amp;lt;/label&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This one works fine and it&amp;#x27;s nice because it means you don&amp;#x27;t have to make
globally unique IDs (typically in a client-rendered app I&amp;#x27;ll generate those
randomly anyway), but it&amp;#x27;s not my favorite mostly because it can be harder to
style things the way I want them to, and
&lt;a href="https://testing-library.com/docs/api-queries#getbylabeltext"&gt;&lt;code&gt;getByLabelText&lt;/code&gt;&lt;/a&gt;
requires you provide a &lt;code&gt;selector&lt;/code&gt; when you do this.&lt;/p&gt;&lt;h2&gt;input[aria-label]&lt;/h2&gt;&lt;pre&gt;&lt;code class="language-html"&gt;&amp;lt;input aria-label=&amp;quot;Username&amp;quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I don&amp;#x27;t really like this approach because it removes a visible label which has
&lt;em&gt;other&lt;/em&gt; accessibility implications.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;You can actually also use the &lt;code&gt;title&lt;/code&gt; attribute, but apparently screen readers
are inconsistent in considering this a label, so just stick with one of the
above methods.&lt;/p&gt;&lt;p&gt;As a bonus, when you properly associate a label to a form control, the clickable
area of the form control includes the label which is especially useful for
checkboxes and people on mobile devices.&lt;/p&gt;&lt;p&gt;Another bonus: you&amp;#x27;ll be able to use
&lt;a href="https://testing-library.com/docs/api-queries#getbylabeltext"&gt;&lt;code&gt;getByLabelText&lt;/code&gt;&lt;/a&gt;
and that&amp;#x27;ll
&lt;a href="https://testing-library.com/docs/guiding-principles"&gt;make your tests resemble the way your software is used&lt;/a&gt;
more closely which is great!&lt;/p&gt;&lt;p&gt;You can read more about this here:
&lt;a href="https://www.w3.org/TR/WCAG20-TECHS/H44.html"&gt;Using label elements to associate text labels with form controls&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;I hope that&amp;#x27;s helpful to you. Again, in addition to making sure that your form
controls are properly labeled, please please try using your form with a keyboard
only. They&amp;#x27;re both very low hanging fruit and can make a big difference in the
accessibility of your forms.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Install and use
&lt;a href="https://github.com/evcohen/eslint-plugin-jsx-a11y"&gt;eslint-plugin-jsx-a11y&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Good luck! 💪&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Join the &lt;a href="https://kcd.im/shurlan-news"&gt;Shurlan News&lt;/a&gt; mailing list for
irregular updates on the progress of my fantasy novel and a discount and early
access to the books when they&amp;#x27;re published.&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/please-stop-building-inaccessible-forms-and-how-to-fix-them"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Static vs Unit vs Integration vs E2E Testing for Frontend Apps]]></title>
<description><![CDATA[In my interview "Testing Practices with
J.B. Rainsberger " available on
TestingJavaScript.com he gave me a metaphor I
really like. He said: You can throw paint against the wall and eventually you might get most of the
wall, but until you go up to…]]></description>
<link>https://kentcdodds.com/blog/unit-vs-integration-vs-e2e-tests</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/unit-vs-integration-vs-e2e-tests</guid>
<pubDate>Mon, 28 Jan 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;In my interview &amp;quot;Testing Practices with
&lt;a href="https://twitter.com/jbrains"&gt;J.B. Rainsberger&lt;/a&gt;&amp;quot; available on
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt; he gave me a metaphor I
really like. He said:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;You can throw paint against the wall and eventually you might get most of the
wall, but until you go up to the wall with a brush, you&amp;#x27;ll never get the
corners. 🖌️&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I love that metaphor in how it applies to testing because it&amp;#x27;s basically saying
that choosing the right testing strategy is the same kind of choice you&amp;#x27;d make
when choosing a brush for painting a wall. Would you use a fine-point brush for
the entire wall? Of course not. That would take too long and the end result
would probably not look very even. Would you use a roller to paint everything,
including around the mounted furnishings your great-great-grandmother brought
over the ocean a hundred years ago? No way. There are different brushes for
different use cases and the same thing applies to tests.&lt;/p&gt;&lt;p&gt;Nearly 1 year ago,
&lt;a href="https://twitter.com/kentcdodds/status/960723172591992832"&gt;created the Testing Trophy&lt;/a&gt;.
Since then &lt;a href="https://twitter.com/Mappletons"&gt;Maggie Appleton&lt;/a&gt; (the mastermind
behind &lt;a href="https://egghead.io"&gt;egghead.io&lt;/a&gt;&amp;#x27;s masterful art/design) created this for
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;:&lt;/p&gt;&lt;p&gt;&lt;a href="https://testingjavascript.com"&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:102.4%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="The Testing Trophy" title="The Testing Trophy" src="https://kentcdodds.com/static/c56de32357ab41ab66d6feb2dfaec567/e11df/testing-trophy.png" srcSet="https://kentcdodds.com/static/c56de32357ab41ab66d6feb2dfaec567/f4a45/testing-trophy.png 259w,https://kentcdodds.com/static/c56de32357ab41ab66d6feb2dfaec567/ef0f6/testing-trophy.png 518w,https://kentcdodds.com/static/c56de32357ab41ab66d6feb2dfaec567/e11df/testing-trophy.png 1000w" sizes="(max-width: 1000px) 100vw, 1000px"/&gt;
&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;In the Testing Trophy, there are 4 types of tests. It shows this text above, but
for the sake of those using assistive technologies (and in case the image fails
to load for you), I&amp;#x27;ll write out what it says here from top to bottom:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;End to End&lt;/strong&gt;: A helper robot that behaves like a user to click around the
app and verify that it functions correctly. Sometimes called &amp;quot;functional
testing&amp;quot; or e2e.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Integration&lt;/strong&gt;: Verify that several units work together in harmony.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Unit&lt;/strong&gt;: Verify that individual, isolated parts work as expected.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Static&lt;/strong&gt;: Catch typos and type errors as you write the code.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The size of these forms of testing on the trophy is relative to the amount of
focus you should give them when testing your applications (in general). I want
to take a deep dive on these different forms of testing, what it means
practically, and what we can do to optimize for the greatest bang for our
testing buck.&lt;/p&gt;&lt;h2&gt;Test Types&lt;/h2&gt;&lt;p&gt;Let&amp;#x27;s look at a few examples of what these kinds of tests are&lt;/p&gt;&lt;h3&gt;End to End&lt;/h3&gt;&lt;p&gt;Typically these will run the entire application (both frontend and backend) and
your test will interact with the app just like a typical user would. These tests
are written with &lt;a href="https://cypress.io"&gt;cypress&lt;/a&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;import {generate} from &amp;#x27;todo-test-utils&amp;#x27;
describe(&amp;#x27;todo app&amp;#x27;, () =&amp;gt; {
it(&amp;#x27;should work for a typical user&amp;#x27;, () =&amp;gt; {
const user = generate.user()
const todo = generate.todo()
// here we&amp;#x27;re going through the registration process.
// I&amp;#x27;ll typically only have one e2e test that does this.
// the rest of the tests will hit the same endpoint
// that the app does so we can skip navigating through that experience.
cy.visitApp()
.getByText(/register/i)
.click()
.getByLabelText(/username)
.type(user.username)
.getByLabelText(/password)
.type(user.password)
.getByText(/login/i)
.click()
.getByLabelText(/add todo/i)
.type(todo.description)
.type(&amp;#x27;{enter}&amp;#x27;)
.getByTestId(&amp;#x27;todo-0&amp;#x27;)
.should(&amp;#x27;have.value&amp;#x27;, todo.description)
.getByLabelText(&amp;#x27;complete&amp;#x27;)
.click()
.getByTestId(&amp;#x27;todo-0&amp;#x27;)
.should(&amp;#x27;have.class&amp;#x27;, &amp;#x27;complete&amp;#x27;)
// etc...
// My E2E tests typically behave similar to how a user would.
// They can sometimes be quite long.
})
})
&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Integration&lt;/h3&gt;&lt;p&gt;The test below renders the full app. This is NOT a requirement of integration
tests and most of my integration tests don&amp;#x27;t render the full app. They will
however render with all the providers used in my app (that&amp;#x27;s what the &lt;code&gt;render&lt;/code&gt;
method from the imaginary &amp;quot;&lt;code&gt;til-client-test-utils&lt;/code&gt;&amp;quot; module does). The idea
behind integration tests is to mock as little as possible. I pretty much only
mock:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Network requests (see &lt;code&gt;axiosMock&lt;/code&gt;)&lt;/li&gt;&lt;li&gt;Components responsible for animation (because who wants to wait for that in
your tests?)&lt;/li&gt;&lt;/ol&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;import React from &amp;#x27;react&amp;#x27;
// this module is mocked via jest&amp;#x27;s __mocks__ directory feature
import axiosMock from &amp;#x27;axios&amp;#x27;
import {render, generate, fireEvent} from &amp;#x27;til-client-test-utils&amp;#x27;
import {init as initAPI} from &amp;#x27;../utils/api&amp;#x27;
import App from &amp;#x27;../app&amp;#x27;
beforeEach(() =&amp;gt; {
window.localStorage.removeItem(&amp;#x27;token&amp;#x27;)
axiosMock.__mock.reset()
initAPI()
})
test(&amp;#x27;login as an existing user&amp;#x27;, async () =&amp;gt; {
const {
getByTestId,
container,
getByText,
getByLabelText,
finishLoading,
} = render(&amp;lt;App /&amp;gt;)
// wait for the app to finish loading the mocked requests
await finishLoading()
fireEvent.click(getByText(/login/i))
expect(window.location.href).toContain(&amp;#x27;login&amp;#x27;)
// fill out form
const fakeUser = generate.loginForm()
const usernameNode = getByLabelText(/username/i)
const passwordNode = getByLabelText(/password/i)
usernameNode.value = fakeUser.username
passwordNode.value = fakeUser.password
// submit form
const {post} = axiosMock.__mock.instance
const token = generate.token(fakeUser)
post.mockImplementationOnce(() =&amp;gt;
Promise.resolve({
data: {user: {...fakeUser, token}},
}),
)
fireEvent.click(getByText(/submit/i))
// wait for the mocked requests to finish
await finishLoading()
// assert calls
expect(axiosMock.__mock.instance.post).toHaveBeenCalledTimes(1)
expect(axiosMock.__mock.instance.post).toHaveBeenCalledWith(
&amp;#x27;/auth/login&amp;#x27;,
fakeUser,
)
// assert the state of the world
expect(window.localStorage.getItem(&amp;#x27;token&amp;#x27;)).toBe(token)
expect(window.location.href).not.toContain(&amp;#x27;login&amp;#x27;)
expect(getByTestId(&amp;#x27;username-display&amp;#x27;).textContent).toEqual(fakeUser.username)
expect(getByText(/logout/i)).toBeTruthy()
})
&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Unit&lt;/h3&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;import &amp;#x27;react-testing-library/cleanup-after-each&amp;#x27;
import &amp;#x27;jest-dom/extend-expect&amp;#x27;
import React from &amp;#x27;react&amp;#x27;
import {render} from &amp;#x27;react-testing-library&amp;#x27;
import ItemList from &amp;#x27;../item-list&amp;#x27;
// Some people don&amp;#x27;t call these a unit test because we&amp;#x27;re render to the DOM with React.
// They&amp;#x27;d tell you to use shallow rendering instead.
// When they tell you this, send them to https://kcd.im/shallow
test(&amp;#x27;renders &amp;quot;no items&amp;quot; when the item list is empty&amp;#x27;, () =&amp;gt; {
const {getByText} = render(&amp;lt;ItemList items={[]} /&amp;gt;)
expect(getByText(/no items/i)).toBeInTheDocument()
})
test(&amp;#x27;renders the items in a list&amp;#x27;, () =&amp;gt; {
const {getByText, queryByText} = render(
&amp;lt;ItemList items={[&amp;#x27;apple&amp;#x27;, &amp;#x27;orange&amp;#x27;, &amp;#x27;pear&amp;#x27;]} /&amp;gt;,
)
// note: with something so simple I might consider using a snapshot instead, but only if:
// 1. the snapshot is small
// 2. we use toMatchInlineSnapshot()
expect(getByText(/apple/i)).toBeInTheDocument()
expect(getByText(/orange/i)).toBeInTheDocument()
expect(getByText(/pear/i)).toBeInTheDocument()
expect(queryByText(/no items/i)).not.toBeInTheDocument()
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Everyone calls this a unit test and they&amp;#x27;re right:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;// pure functions are the BEST for unit testing and I LOVE using jest-in-case for them!
import cases from &amp;#x27;jest-in-case&amp;#x27;
import fizzbuzz from &amp;#x27;../fizzbuzz&amp;#x27;
cases(
&amp;#x27;fizzbuzz&amp;#x27;,
({input, output}) =&amp;gt; expect(fizzbuzz(input)).toBe(output),
[
[1, &amp;#x27;1&amp;#x27;],
[2, &amp;#x27;2&amp;#x27;],
[3, &amp;#x27;Fizz&amp;#x27;],
[5, &amp;#x27;Buzz&amp;#x27;],
[9, &amp;#x27;Fizz&amp;#x27;],
[15, &amp;#x27;FizzBuzz&amp;#x27;],
[16, &amp;#x27;16&amp;#x27;],
].map(([input, output]) =&amp;gt; ({title: `${input} =&amp;gt; ${output}`, input, output})),
)
&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Static&lt;/h3&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;// can you spot the bug?
// I&amp;#x27;ll bet ESLint&amp;#x27;s for-direction rule could
// catch it faster than you in a code review 😉
for (var i = 0; i &amp;lt; 10; i--) {
console.log(i)
}
const two = &amp;#x27;2&amp;#x27;
// ok, this one&amp;#x27;s contrived a bit,
// but TypeScript will tell you this is bad:
const result = add(1, two)
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Why do we test again?&lt;/h2&gt;&lt;p&gt;I think it&amp;#x27;s important to remember why it is that we write tests in the first
place. Why do &lt;em&gt;you&lt;/em&gt; write tests? Is it because I told you to? Is it because your
PR will get rejected unless it includes tests? Is it because testing enhances
your workflow?&lt;/p&gt;&lt;p&gt;The biggest and most important reason that I write tests is &lt;strong&gt;CONFIDENCE&lt;/strong&gt;. I
want to be confident that the code I&amp;#x27;m writing for the future wont break the app
that I have running in production today. So whatever I do, I want to make sure
that the kinds of tests I write bring me the most confidence possible and I need
to be cognizant of the trade-offs I&amp;#x27;m making when testing.&lt;/p&gt;&lt;h2&gt;Let&amp;#x27;s talk trade-offs&lt;/h2&gt;&lt;p&gt;There are some important elements to the testing trophy I want to call out in
this picture (ripped from &lt;a href="http://kcd.im/confident-react"&gt;my slides&lt;/a&gt;):&lt;/p&gt;&lt;p&gt;&lt;a href="https://slides.com/kentcdodds/confident-react#/3/5"&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1035px"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:70.73333333333333%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="The Testing Trophy with arrows indicating the trade-offs" title="The Testing Trophy with arrows indicating the trade-offs" src="https://kentcdodds.com/static/c331ec0658e3d2927db08b6e4946e266/17fa4/confidence-coefficient.png" srcSet="https://kentcdodds.com/static/c331ec0658e3d2927db08b6e4946e266/f4a45/confidence-coefficient.png 259w,https://kentcdodds.com/static/c331ec0658e3d2927db08b6e4946e266/ef0f6/confidence-coefficient.png 518w,https://kentcdodds.com/static/c331ec0658e3d2927db08b6e4946e266/17fa4/confidence-coefficient.png 1035w,https://kentcdodds.com/static/c331ec0658e3d2927db08b6e4946e266/8e846/confidence-coefficient.png 1500w" sizes="(max-width: 1035px) 100vw, 1035px"/&gt;
&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;The arrows on the image signify three trade-offs you make when writing automated
tests:&lt;/p&gt;&lt;h3&gt;Cost: ¢ heap ➡ 💰🤑💰&lt;/h3&gt;&lt;p&gt;As you move up the testing trophy, the tests become more costly. This comes in
the form of actual money to run the tests in a continuous integration
environment, but also in the time it takes engineers to write and maintain each
individual test.&lt;/p&gt;&lt;p&gt;The higher up the trophy you go, the more points of failure there are and
therefore the more likely it is that a test will break, leading to more time
needed to analyze and fix the tests. &lt;strong&gt;Keep this in mind because it&amp;#x27;s
important&lt;/strong&gt; #foreshadowing...&lt;/p&gt;&lt;h3&gt;Speed: 🏎💨 ➡ 🐢&lt;/h3&gt;&lt;p&gt;As you move up the testing trophy, the tests typically run slower. This is due
to the fact that the higher you are on the testing trophy, the more code your
test is running. Unit tests typically test something small that has no
dependencies or will mock those dependencies (effectively swapping what could be
thousands of lines of code with only a few). &lt;strong&gt;Keep this in mind because it&amp;#x27;s
important&lt;/strong&gt; #foreshadowing...&lt;/p&gt;&lt;h3&gt;Confidence: Simple problems 👌 ➡ Big problems 😖&lt;/h3&gt;&lt;p&gt;The cost and speed trade-offs are typically referenced when people talk about
the testing pyramid 🔺. If those were the only trade-offs though, then I would
focus 100% of my efforts on unit tests and totally ignore any other form of
testing when regarding the testing pyramid. Of course we shouldn&amp;#x27;t do that and
this is because of one super important principle that you&amp;#x27;ve probably heard me
say before:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;a href="https://twitter.com/kentcdodds/status/977018512689455106"&gt;The more your tests resemble the way your software is used, the more confidence they can give you.&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;What does this mean? It means that there&amp;#x27;s no better way to ensure that your
Aunt Marie will be able to file her taxes using your tax software than actually
having her do it. But we don&amp;#x27;t want to wait on Aunt Marie to find our bugs for
us right? It would take too long and she&amp;#x27;d probably miss some features that we
should probably be testing. Compound that with the fact that we&amp;#x27;re regularly
releasing updates to our software there&amp;#x27;s no way any amount of humans would be
able to keep up.&lt;/p&gt;&lt;p&gt;So what do we do? &lt;strong&gt;We make trade-offs&lt;/strong&gt;. And how do we do that? We write
software that tests our software. And the trade-off we&amp;#x27;re always making when we
do that is now our tests don&amp;#x27;t resemble the way our software is used as reliably
as when we had Aunt Marie testing our software. But we do it because we solve
real problems we had with that approach. And that&amp;#x27;s what we&amp;#x27;re doing at every
level of the testing trophy.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;As you move up the testing trophy, you&amp;#x27;re increasing what I call the
&amp;quot;confidence coefficient.&amp;quot;&lt;/strong&gt; This is the relative confidence that each test can
get you at that level. You can imagine that above the trophy is manual testing.
That would get you really great confidence from those tests, but the tests would
be really expensive and slow.&lt;/p&gt;&lt;p&gt;Earlier I told you to remember two things:&lt;/p&gt;&lt;blockquote&gt;&lt;ul&gt;&lt;li&gt;The higher up the trophy you go, the more points of failure there are and
therefore the more likely it is that a test will break&lt;/li&gt;&lt;li&gt;Unit tests typically test something small that has no dependencies or will
mock those dependencies (effectively swapping what could be thousands of
lines of code with only a few).&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;p&gt;What those are saying is that the lower the trophy you are, the less code your
tests are testing. If you&amp;#x27;re operating at a low level you need more tests to
cover the same number of lines of code in your application as a single test
could higher up the trophy. In fact, as you go lower down the testing trophy,
there are some things that are impossible to test.&lt;/p&gt;&lt;p&gt;In particular, static analysis tools are incapable of giving you confidence in
your business logic. Unit tests are incapable of ensuring that when you call
into a dependency that you&amp;#x27;re calling it appropriately (though you can make
assertions on how it&amp;#x27;s being called, you can&amp;#x27;t ensure that it&amp;#x27;s being called
properly with a unit test). UI Integration tests are incapable of ensuring that
you&amp;#x27;re passing the right data to your backend and that you respond to and parse
errors correctly. End to End tests are pretty darn capable, but typically you&amp;#x27;ll
run these in a non-production environment (production-like, but not production)
to trade-off that confidence for practicality.&lt;/p&gt;&lt;p&gt;Let&amp;#x27;s go the other way now. At the top of the testing trophy, if you try to use
an E2E test to check that typing in a certain field and clicking the submit
button for an edge case in the integration between the form and the URL
generator, you&amp;#x27;re doing a lot of setup work by running the entire application
(backend included). That might be more suitable for an integration test. If you
try to use an integration test to hit an edge case for the coupon code
calculator, you&amp;#x27;re likely doing a fair amount of work in your setup function to
make sure you can render the components that use the coupon code calculator and
you could cover that edge case better in a unit test. If you try to use a unit
test to verify what happens when you call your add function with a string
instead of a number you could be much better served using a static type checking
tool like TypeScript.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;Every level comes with its own trade-offs. An E2E test has more points of
failure making it often harder to track down what code caused the breakage, but
it also means that your test is giving you more confidence. This is especially
useful if you don&amp;#x27;t have as much time to write tests. I&amp;#x27;d rather have the
confidence and be faced with tracking down why it&amp;#x27;s failing, than not having
caught the problem via a test in the first place.&lt;/p&gt;&lt;p&gt;In the end &lt;strong&gt;I don&amp;#x27;t really care about the distinctions.&lt;/strong&gt; If you want to call
my unit tests integration tests or even E2E tests (as some people have 🤷‍♂️) then
so be it. What I&amp;#x27;m interested in is whether I&amp;#x27;m confident that when I ship my
changes, my code satisfies the business requirements and I&amp;#x27;ll use a mix of the
different testing strategies to accomplish that goal.&lt;/p&gt;&lt;p&gt;Good luck!&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;&lt;strong&gt;Learn more about Testing from me&lt;/strong&gt;:&lt;/p&gt;&lt;p&gt;Here are a few relevant blog posts for you as well:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/blog/testing-implementation-details"&gt;Testing Implementation Details&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/blog/react-hooks-whats-going-to-happen-to-my-tests"&gt;React Hooks: What’s going to happen to my tests?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/blog/common-testing-mistakes"&gt;Common Testing Mistakes&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/blog/ui-testing-myths"&gt;UI Testing Myths&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/blog/the-merits-of-mocking"&gt;The Merits of Mocking&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/blog/react-is-an-implementation-detail"&gt;React is an implementation detail&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/blog/eliminate-an-entire-category-of-bugs-with-a-few-simple-tools"&gt;Eliminate an entire category of bugs with a few simple tools&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/blog/why-youve-been-bad-about-testing"&gt;Why you’ve been bad about testing&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/blog/demystifying-testing"&gt;Demystifying Testing&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/blog/confidently-shipping-code"&gt;Confidently Shipping Code&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/blog/why-i-never-use-shallow-rendering"&gt;Why I Never Use Shallow Rendering&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/blog/test-isolation-with-react"&gt;Test Isolation with React&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/blog/but-really-what-is-a-javascript-mock"&gt;But really, what is a JavaScript mock?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/blog/but-really-what-is-a-javascript-test"&gt;But really, what is a JavaScript test?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/blog/effective-snapshot-testing"&gt;Effective Snapshot Testing&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/blog/making-your-ui-tests-resilient-to-change"&gt;Making your UI tests resilient to change&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/blog/write-tests"&gt;Write tests. Not too many. Mostly integration.&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://peterhrynkow.com/testing/2019/01/01/testing-atoms-and-molecules.html"&gt;Testing Atoms &amp;amp; Molecules&lt;/a&gt;
by &lt;a href="https://twitter.com/peterhry"&gt;Peter Hrynkow&lt;/a&gt; is a great blog post about
where to focus your testing (using a connected Redux component as an example)&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.javascriptjanuary.com/blog/react-hooks-array-destructuring-fundamentals"&gt;React Hooks: Array Destructuring Fundamentals&lt;/a&gt; -
This may look familiar. It&amp;#x27;s a cross-post of my blog from a while back on the
fantastic &lt;a href="https://www.javascriptjanuary.com"&gt;JavaScriptJanuary.com&lt;/a&gt; by the
amazing &lt;a href="https://twitter.com/editingemily"&gt;Emily Freeman&lt;/a&gt;. Checkout the other
posts!&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/unit-vs-integration-vs-e2e-tests"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[2018 in Review]]></title>
<description><![CDATA[Whether you've had a great 2018 or not, I think it's important to look back and
reflect on your accomplishments for the year. You've probably done more than you
think you have. In this newsletter, I'm going to share with you some of my
professional…]]></description>
<link>https://kentcdodds.com/blog/2018-in-review</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/2018-in-review</guid>
<pubDate>Mon, 14 Jan 2019 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;Whether you&amp;#x27;ve had a great 2018 or not, I think it&amp;#x27;s important to look back and
reflect on your accomplishments for the year. You&amp;#x27;ve probably done more than you
think you have. In this newsletter, I&amp;#x27;m going to share with you some of my
professional (and unprofessional) accomplishments of which I&amp;#x27;m particularly
proud and give a few hints as to what I&amp;#x27;m planning for 2019 (which is actually
mostly a secret and surprise 😃).&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Note: I don&amp;#x27;t want to bother with trying to sort these in any particular
order, so... they&amp;#x27;re not in any particular order...&lt;/p&gt;&lt;/blockquote&gt;&lt;h2&gt;&lt;a href="https://github.com/testing-library/react-testing-library"&gt;react-testing-library&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;This year I
&lt;a href="https://github.com/testing-library/react-testing-library/commit/4f16c6e6b356fae1ad92f59eebeb1a8000f60714"&gt;created&lt;/a&gt;
and
&lt;a href="https://kentcdodds.com/blog/introducing-the-react-testing-library"&gt;introduced react-testing-library&lt;/a&gt;.
It has &lt;a href="https://www.npmtrends.com/react-testing-library"&gt;grown a lot&lt;/a&gt; since
then. &lt;a href="https://spectrum.chat/testing-library"&gt;The spectrum community&lt;/a&gt; has
&lt;a href="https://twitter.com/kentcdodds/status/1079523389553790976"&gt;over 300 members now&lt;/a&gt;.
We&amp;#x27;ve &lt;a href="https://twitter.com/Saifadin/status/1079746658882195457"&gt;really&lt;/a&gt;
&lt;a href="https://twitter.com/blankmannow/status/1079358441380954112"&gt;had&lt;/a&gt;
&lt;a href="https://twitter.com/LaurenBeatty13/status/1079489139433762819"&gt;a&lt;/a&gt;
&lt;a href="https://twitter.com/littlekope0903/status/1077045168195452928"&gt;whole&lt;/a&gt;
&lt;a href="https://twitter.com/fatihkupkil/status/1077165153056157699"&gt;lot&lt;/a&gt;
&lt;a href="https://twitter.com/jeanbauerr/status/1076935301166260227"&gt;of&lt;/a&gt;
&lt;a href="https://twitter.com/housecor/status/1074319158362415106"&gt;love&lt;/a&gt;...
&lt;a href="https://twitter.com/BjoernRicks/status/1070596680540672000"&gt;like&lt;/a&gt;,
&lt;a href="https://twitter.com/jaredpalmer/status/1060912456829231104"&gt;a&lt;/a&gt;
&lt;a href="https://twitter.com/jaredpalmer/status/1060348319485095936"&gt;lot&lt;/a&gt;
&lt;a href="https://twitter.com/th__chia/status/1058542488816803840"&gt;of&lt;/a&gt;
&lt;a href="https://twitter.com/antontelesh/status/976364558586667009"&gt;sweet&lt;/a&gt;
&lt;a href="https://twitter.com/skidding/status/1054718393209753600"&gt;tweets&lt;/a&gt;
&lt;a href="https://twitter.com/housecor/status/1047150875502960641"&gt;of&lt;/a&gt;
&lt;a href="https://twitter.com/JeffreyRussom/status/1003996108270555136"&gt;appreciation&lt;/a&gt;
(&lt;a href="https://twitter.com/dan_abramov/status/1078709118863593472"&gt;Dan even called it &amp;quot;not bad&amp;quot;&lt;/a&gt;).
Shout out to
&lt;a href="https://twitter.com/ryanflorence/status/975424602699530240"&gt;Ryan Florence for the name&lt;/a&gt;
and &lt;a href="https://twitter.com/thymikee/status/1050372496971706368"&gt;Michał Pierzchała&lt;/a&gt;
for making
&lt;a href="https://github.com/callstack/react-native-testing-library"&gt;react-native-testing-library&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;I&amp;#x27;m super proud of what we&amp;#x27;ve accomplished here. The
&lt;a href="https://github.com/testing-library/react-testing-library/blob/master/README.md#contributors"&gt;react-testing-library all contributors table&lt;/a&gt;
lists 63 awesome people, and the
&lt;a href="https://github.com/testing-library/dom-testing-library/blob/master/README.md#contributors"&gt;dom-testing-library all contributors table&lt;/a&gt;
lists 46 (many repeats, but not all). These people are amazing and I really
appreciate what they&amp;#x27;ve done. I don&amp;#x27;t want to leave anyone out, but I would like
to give a special shout out to these folks: &lt;a href="https://twitter.com/Gpx"&gt;Giorgio&lt;/a&gt;,
&lt;a href="https://twitter.com/TensorNo"&gt;Alex Krolick&lt;/a&gt;,
&lt;a href="https://twitter.com/sompylasar"&gt;Ivan Babak&lt;/a&gt;,
&lt;a href="https://twitter.com/gnapse"&gt;Ernesto García&lt;/a&gt;, and
&lt;a href="https://twitter.com/lgandecki"&gt;Łukasz Gandecki&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Creating this open source software and the community of awesome people that has
been built around it is probably one of my finest accomplishments of 2019. If
you&amp;#x27;d like to hear more about how this software came to be, you can watch
&lt;a href="https://youtu.be/nw-GFMW8LSQ"&gt;S05E12 Modern Web Podcast - Testing&lt;/a&gt; or listen to
&lt;a href="https://devchat.tv/react-round-up/rru-043-testing-react-apps-without-testing-implementation-details-with-kent-c-dodds"&gt;RRU 043: Testing React Apps Without Testing Implementation Details with Kent C. Dodds&lt;/a&gt;.&lt;/p&gt;&lt;h2&gt;&lt;a href="https://nanowrimo.org"&gt;National Novel Writing Month&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Of all non-professional things I&amp;#x27;ve done this year, I&amp;#x27;m most proud of this one.
If you didn&amp;#x27;t know, I wrote a 50,000 word novel in the month of November for
&lt;a href="https://nanowrimo.org"&gt;NaNoWriMo&lt;/a&gt;. This was the first year I tried and I WON!&lt;/p&gt;&lt;p&gt;Back in August, I decided I wanted to become better at storytelling because my
kids are always asking me to tell them stories and I wasn&amp;#x27;t very good at it.
Something reminded me of my friend in college who had written a novel in one
month for NaNoWriMo. I had been listening to a LOT of
&lt;a href="https://brandonsanderson.com"&gt;Brandon Sanderson&lt;/a&gt; recently (more on this later)
and decided to try writing my own Sanderson-style fantasy novel.&lt;/p&gt;&lt;p&gt;I spent the next few months preparing. I listened to
&lt;a href="https://storygrid.simplecast.fm"&gt;the entire story grid podcast&lt;/a&gt;, four seasons
of &lt;a href="https://writingexcuses.com"&gt;the writing excuses podcast&lt;/a&gt; (they have a lot of
seasons), I talked through the story, characters, magic, and more with my wife
and she gave me some brilliant ideas, I made
&lt;a href="https://workflowy.com/s/--B.0EZBOxYZWM"&gt;an in depth outline and took notes&lt;/a&gt;
(&lt;a href="https://workflowy.com/invite/a9f7933.lnx"&gt;workflowy is awesome by the way&lt;/a&gt;),
and helped inspire the creation of &lt;a href="https://kcd.im/dww"&gt;DevsWhoWrite discord&lt;/a&gt;
where I joined several other awesome devs who... well... write 😉 (feel free to
join us!).&lt;/p&gt;&lt;p&gt;The end result is &lt;a href="https://kcd.im/shurlan"&gt;Shurlan&lt;/a&gt;. I&amp;#x27;m super proud of it and
still working on editing to prepare it for publication! Here&amp;#x27;s a little summary:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;The Immortal family has ruled Shurlan for thousands of years. Thanks to their
wisdom, the perfect society has been formed and peace and plenty graces
Shurlan. But when the food allotments start to dwindle, a rebellion begins,
and only those with secret magic abilities can stop them.&lt;/p&gt;&lt;p&gt;Kyana, an extremely skilled gravity displacer (known as a drifter) is chosen
by Lord Talmar of the Immortal family to do the impossible task of recruiting
non-displacers and training them to learn a displacement skill. They need to
find and stop the rebellion before they steal the harvest and their families
starve.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;This is a &lt;a href="https://en.wikipedia.org/wiki/Hard_fantasy"&gt;hard fantasy&lt;/a&gt; novel. That
means that the magic system and world are intended to be rational and knowable
(it&amp;#x27;s also really cool). It&amp;#x27;s also
&lt;a href="https://en.wikipedia.org/wiki/Juvenile_fantasy"&gt;juvenile fantasy&lt;/a&gt;, which means
it&amp;#x27;s an enjoyable read for adults and kids alike (think Harry Potter).&lt;/p&gt;&lt;p&gt;What I think makes this book special is the message I&amp;#x27;m trying to communicate,
the world I&amp;#x27;ve created, the characters, and the magic system.&lt;/p&gt;&lt;p&gt;I&amp;#x27;ve totally immersed myself in this world and the world of writing. I&amp;#x27;m
planning on attending writing conferences this year to do some networking and
improving my craft. I&amp;#x27;m looking forward to November 2019 when I&amp;#x27;ll write book 2
in the Shurlan series. I have the concept for 4 series (3 books each) in this
world. Feeling determined :)&lt;/p&gt;&lt;h2&gt;&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;This was a HUGE effort by me and the good folks at
&lt;a href="https://egghead.io"&gt;egghead.io&lt;/a&gt;. It&amp;#x27;s the equivalent of 7 full sized egghead.io
courses + 9 podcast episodes. It was a TON of work and people LOVE it. So I&amp;#x27;m
really happy with this.&lt;/p&gt;&lt;h2&gt;&lt;a href="https://kentcdodds.com/blog/tools-without-config"&gt;paypal-scripts&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;I started this project in August of 2017, but most of the work was done in 2018.
It&amp;#x27;s basically a single tool that consolidates a bunch of other tools common to
PayPal projects (both applications and reusable modules published to our
internal npm registry). Think of it like create-react-app&amp;#x27;s react-scripts, or
ember-cli, or angular-cli. But it does a lot more than just the build/tests.
Here are all the available scripts as of today:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;build
clean
dev
format
gh-pages
lint
pre-commit
release
remark
test
typecheck
validate
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It would take another blog post to explain what these all do and how it does
them. But suffice it to say, this was a herculean effort that took most of my
time at work this year.&lt;/p&gt;&lt;p&gt;One huge accomplishment around paypal-scripts was in the last month I decided to
adopt TypeScript (that&amp;#x27;s a blog post for another time) and I was heads down
updating all the tools to work with &lt;code&gt;.ts&lt;/code&gt; and &lt;code&gt;.tsx&lt;/code&gt; files.&lt;/p&gt;&lt;p&gt;What makes this project such a big deal is that it&amp;#x27;s very soon to be the basis
of the default template project at PayPal we have called the &amp;quot;sample-app.&amp;quot; Every
new app started at PayPal is basically a fork of this &amp;quot;sample-app.&amp;quot; So because
of the work that I and others have done, every new app at PayPal will be written
in TypeScript, use Jest, React, react-testing-library, emotion, webpack, babel,
prettier, and eslint. And what makes it better is those apps wont have to worry
about keeping those tools up to date saving dozens of developer hours a year PER
PROJECT. I&amp;#x27;m really proud of this accomplishment.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;(Before you ask, this will not be open sourced, it&amp;#x27;s too PayPal specific, but
you might be interested in forking
&lt;a href="https://github.com/kentcdodds/kcd-scripts"&gt;kcd-scripts&lt;/a&gt;).&lt;/p&gt;&lt;/blockquote&gt;&lt;h2&gt;&lt;a href="https://paypal.me"&gt;PayPal.me&lt;/a&gt; rewrite&lt;/h2&gt;&lt;p&gt;At the beginning of the year, PayPal decided to make some significant changes to
parts of the experience and that had a big impact on how
&lt;a href="https://paypal.me"&gt;PayPal.me&lt;/a&gt; was supposed to work. The original implementation
would be hard to upgrade incrementally and the app is pretty simple anyway, so
we decided to do a complete rewrite. We used paypal-scripts for all the tooling
(it was the first major production app to do so) and we were able to get the
tooling side of things done without much configuration or wiring together tools
of any kind (I had to make quite a few adjustments to paypal-scripts though 😅
but it&amp;#x27;s good now I promise). That was an awesome experience for paypal-scripts
and I&amp;#x27;m really excited to see the experience for everyone else at PayPal as
adoption increases.&lt;/p&gt;&lt;p&gt;Building the app was great. We ended up using
&lt;a href="https://github.com/jamiebuilds/unstated"&gt;unstated&lt;/a&gt; for state management and
we&amp;#x27;re pretty happy with it. We used
&lt;a href="https://github.com/paypal/glamorous"&gt;glamorous&lt;/a&gt; (decided that before deciding
to deprecate glamorous, we&amp;#x27;ll be moving to emotion eventually). The backend was
GraphQL (huge thanks to &lt;a href="https://twitter.com/arnab0831"&gt;Arnab Banik&lt;/a&gt; who did
most of the work there). It&amp;#x27;s a pretty simple app, so we&amp;#x27;re not using Apollo or
anything, just
&lt;a href="https://www.npmjs.com/package/graphql-request"&gt;&lt;code&gt;graphql-request&lt;/code&gt;&lt;/a&gt; and that
worked well for our needs.&lt;/p&gt;&lt;p&gt;Anyway, really happy with how that turned out :)&lt;/p&gt;&lt;h2&gt;Open Source&lt;/h2&gt;&lt;p&gt;Aside from creating react-testing-library (and dom-testing-library) this year,
there are a few other accomplishments I had this year/useless numbers in the
realm of Open Source that I&amp;#x27;d like to mention. Here are a few numbers:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Hit 500 repos (most of them are nonsense, I do have over 100 published npm
packages though, so there&amp;#x27;s that).&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/facebook/create-react-app/pull/3675"&gt;Added &lt;code&gt;babel-plugin-macros&lt;/code&gt; to &lt;code&gt;create-react-app&lt;/code&gt;&lt;/a&gt;
and it was &lt;a href="https://github.com/gatsbyjs/gatsby/pull/7129"&gt;added to gatsby&lt;/a&gt;.
There are
&lt;a href="https://www.npmjs.com/browse/depended/babel-plugin-macros"&gt;over 200 dependents published on npm&lt;/a&gt;!&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/search?q=created%3A%3E2018-01-01+is%3Aissue+author%3Akentcdodds&amp;amp;type=Issues"&gt;I opened 134 issues&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/search?q=created%3A%3E2018-01-01+is%3Apr+author%3Akentcdodds+-user%3Akentcdodds"&gt;I created 86 PRs&lt;/a&gt;
(&lt;a href="https://github.com/search?utf8=%E2%9C%93&amp;amp;q=created%3A%3E2018-01-01+is%3Apr+author%3Akentcdodds+-user%3Akentcdodds+is%3Amerged&amp;amp;ref=simplesearch"&gt;73 were merged&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/search?q=created%3A%3E2018-01-01+is%3Apr+reviewed-by%3Akentcdodds&amp;amp;type=Issues"&gt;I reviewed 802 PRs&lt;/a&gt;...
WOW. 🤯&lt;/li&gt;&lt;li&gt;I &lt;a href="https://github.com/paypal/glamorous/issues/419"&gt;deprecated glamorous&lt;/a&gt; in
favor of &lt;a href="https://emotion.sh"&gt;emotion.sh&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Published v2 and v3 of &lt;a href="https://github.com/downshift-js/downshift"&gt;downshift&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;There are now
&lt;a href="https://github.com/search?q=.all-contributorsrc+in%3Apath&amp;amp;type=Code&amp;amp;utf8=%E2%9C%93"&gt;over 2k &lt;code&gt;.all-contributorsrc&lt;/code&gt; files on GitHub&lt;/a&gt;
😱&lt;/li&gt;&lt;li&gt;All in all,
&lt;a href="https://github.com/kentcdodds"&gt;I had 2,337 GitHub contributions in the last year&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;&lt;a href="https://kcd.im/youtube"&gt;My YouTube Channel&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;This was the year I decided to do week-daily livestreams on
&lt;a href="https://kcd.im/youtube"&gt;my YouTube channel&lt;/a&gt;:
&lt;a href="https://kcd.im/devtips"&gt;Dev Tips with Kent&lt;/a&gt;. I&amp;#x27;ve got over 100 videos on the
dev tips playlist. Some of them are longer than others, some of them are more
coherent than others, but altogether they represent a great resource for people
to learn things from JavaScript to testing to React to Babel to more and more :)&lt;/p&gt;&lt;p&gt;I also have a playlist called
&lt;a href="https://youtube.com/playlist?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;Talks and workshops from Kent C. Dodds&lt;/a&gt;
with over 60 videos. More on this later.&lt;/p&gt;&lt;p&gt;Altogether, this year I&amp;#x27;ve really been pushing content onto YouTube and
&lt;a href="https://twitter.com/kentcdodds/status/1073589861054070784"&gt;hit over 10k subscribers&lt;/a&gt;.
My videos got over 260k views this year (I am of course excluding
&lt;a href="https://youtu.be/t6q5_7fVjEg"&gt;my smiley face video&lt;/a&gt;
&lt;a href="https://github.com/kentcdodds/ama/issues/290"&gt;which was stolen&lt;/a&gt; and has 3.7
million views now).&lt;/p&gt;&lt;h2&gt;Conferences&lt;/h2&gt;&lt;p&gt;I gave a lot of talks this year, you can find all the available recordings on
&lt;a href="https://youtube.com/playlist?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;my YouTube playlist&lt;/a&gt;.
I spoke at 7 conferences and several meetups. I was especially proud to deliver
&lt;a href="https://youtu.be/M9X2qGddHkU?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;my first keynote&lt;/a&gt;
at &lt;a href="https://infinite.red/ChainReactConf"&gt;Chain React&lt;/a&gt; which was awesome.&lt;/p&gt;&lt;p&gt;I gave
&lt;a href="https://youtu.be/AiJ8tRRH0f8?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;a similar talk&lt;/a&gt;
at &lt;a href="https://www.reactrally.com"&gt;React Rally&lt;/a&gt; which is my favorite conference and
has been a dream of mine since year one.&lt;/p&gt;&lt;p&gt;I try to avoid traveling to conferences, so most of the conferences I spoke at
were either local or remote. I did travel to San Antonio for
&lt;a href="https://www.assertjs.com"&gt;Assert.js&lt;/a&gt; and Portland for
&lt;a href="https://infinite.red/ChainReactConf"&gt;Chain React&lt;/a&gt;. The only other travel I did
this year was to PayPal offices to give workshops/trainings in San Jose and
Austin, TX.&lt;/p&gt;&lt;h2&gt;Other&lt;/h2&gt;&lt;p&gt;Here are some other interesting facts/accomplishments from 2018:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://twitter.com/ryanflorence/status/1062114045417873408"&gt;I read the Book of Mormon&lt;/a&gt;
again.&lt;/li&gt;&lt;li&gt;&lt;a href="https://twitter.com/kentcdodds"&gt;Twitter&lt;/a&gt;: I went from
&lt;a href="https://twitter.com/kentcdodds/status/955863656788643840"&gt;25k followers&lt;/a&gt; to
almost 50k.&lt;/li&gt;&lt;li&gt;&lt;a href="https://kcd.im/news"&gt;Newsletter&lt;/a&gt;: I went from
&lt;a href="https://twitter.com/kentcdodds/status/973023708473278465"&gt;less than 5k subscribers&lt;/a&gt;
to over 10k.&lt;/li&gt;&lt;li&gt;&lt;a href="https://brandonsanderson.com"&gt;Brandon Sanderson&lt;/a&gt;: I listened to almost 30
DAYS worth of time of Brandon Sanderson fantasy novels in 2018. I listen at
2.9x speed, so it amounts to ~10 days of time, but still. I&amp;#x27;ve filled my ears
with his words this year!&lt;/li&gt;&lt;li&gt;I posted 62 new blog posts on &lt;a href="https://kentcdodds.com/blog"&gt;my blog&lt;/a&gt; on subjects around JavaScript,
Testing, React, as well as career advice.&lt;/li&gt;&lt;li&gt;In 2018, I spent most of my course time on testingjavascript.com, but I did
manage to make a complete update to
&lt;a href="https://kcd.im/advanced-react"&gt;Advanced React Component Patterns&lt;/a&gt; and make
&lt;a href="https://egghead.io/courses/simplify-react-apps-with-react-hooks"&gt;Simplify React Apps with React Hooks&lt;/a&gt;
as well as &lt;a href="https://kcd.im/hooks-and-suspense"&gt;Hooks &amp;amp; Suspense Playlist&lt;/a&gt;. I
don&amp;#x27;t have easy access to stats, but in last night&amp;#x27;s egghead stats email
people watched ~26 hours of my content yesterday and that&amp;#x27;s pretty typical. I
think that&amp;#x27;s pretty neat!&lt;/li&gt;&lt;li&gt;Back in April, I made a trip to Minneapolis to record workshops for
&lt;a href="https://kcd.im/fem"&gt;Frontend Masters&lt;/a&gt;. We made three (almost four) courses
out of that trip:
&lt;a href="https://frontendmasters.com/courses/advanced-react-patterns"&gt;Advanced React Patterns&lt;/a&gt;,
&lt;a href="https://frontendmasters.com/courses/testing-react"&gt;Testing React Applications, v2&lt;/a&gt;,
and
&lt;a href="https://frontendmasters.com/courses/testing-practices-principles"&gt;JavaScript Testing Practices and Principles&lt;/a&gt;.
I&amp;#x27;m really happy about how those turned out!&lt;/li&gt;&lt;li&gt;For the first part of the year,
&lt;a href="https://twitter.com/ryanflorence"&gt;Ryan Florence&lt;/a&gt; made
&lt;a href="https://twitter.com/workshop_me"&gt;Workshop.me&lt;/a&gt;. I gave 5 workshops (two on
testing, two on advanced react, and one on beginning react) through
workshop.me and it was awesome (though short-lived).&lt;/li&gt;&lt;li&gt;I gave 4 other workshops this year all of which you can find on
&lt;a href="https://youtube.com/playlist?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;my YouTube playlist&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;What&amp;#x27;s next in 2019&lt;/h2&gt;&lt;p&gt;I&amp;#x27;m really excited about plans I have for 2019. I&amp;#x27;m not going to give away all
my surprises, but here are a few things:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;I&amp;#x27;m turning my &lt;a href="https://kcd.im/3-mins"&gt;3 minutes with Kent podcast&lt;/a&gt; into a
week-daily Q&amp;amp;A. Give it a look, subscribe, and ask your own question on my
AMA: &lt;a href="https://kcd.im/ama"&gt;kcd.im/ama&lt;/a&gt;&lt;/li&gt;&lt;li&gt;I&amp;#x27;m revamping &lt;a href="https://kentcdodds.com"&gt;my website&lt;/a&gt; using Gatsby and a bunch of
other cool tools. I&amp;#x27;ll definitely blog about it. I&amp;#x27;m actually kinda excited
about it :) I&amp;#x27;ll also be moving my blog from Medium to my website with gatsby
and hopefully automate more parts of this newsletter stuff :)&lt;/li&gt;&lt;li&gt;Remember TestingJavaScript.com? How would you like something like that for
learning React? But even bigger? From total beginner to JS to total React
professional? This is going to be enormous.&lt;/li&gt;&lt;li&gt;I avoid traveling as much as possible, but I want to give more workshops this
year than I gave last year. So I&amp;#x27;m going to do online workshops. There are
&lt;a href="https://twitter.com/kentcdodds/status/1022675523154014209"&gt;a lot of benefits to remote workshops&lt;/a&gt;.
I&amp;#x27;ve done it and I know how to make up for the difficulties of not being there
in person. You&amp;#x27;re going to want to take advantage of these!&lt;/li&gt;&lt;li&gt;At PayPal, I&amp;#x27;m working on a component library. I imagine there are some
opportunities to open source the generic stuff (HOOKS!)&lt;/li&gt;&lt;li&gt;I&amp;#x27;m scheduled to speak and give workshops at
&lt;a href="https://react.amsterdam"&gt;React Amsterdam&lt;/a&gt; in April! See you there? I have at
least one other conference that I&amp;#x27;ll probably be speaking at soon as well. I
expect I&amp;#x27;ll be speaking a lot around here in Utah as well.&lt;/li&gt;&lt;li&gt;I have about 15 fantasy novels in mind for the Shurlan Universe. I&amp;#x27;m
definitely planning on writing one each year in November and working
throughout the year to get each published. I&amp;#x27;m feeling pretty optimistic and
motivated about this whole novel writing stuff :)&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;I hope you take the opportunity to look back at your year and see what you&amp;#x27;ve
accomplished. Then make some goals to become even better than you are now.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&amp;quot;There is nothing noble in being superior to your fellow man; true nobility is
being superior to your former self.&amp;quot; ― Ernest Hemingway&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I wish you the very best and happiest New Year!&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://devchat.tv/react-round-up/rru-043-testing-react-apps-without-testing-implementation-details-with-kent-c-dodds"&gt;RRU 043: Testing React Apps Without Testing Implementation Details with Kent C. Dodds&lt;/a&gt; -
The ReactRoundUp podcast had me on to talk about testing!&lt;/li&gt;&lt;li&gt;&lt;a href="https://mhme-blog.now.sh/2018/december/testing-software.html"&gt;Testing Software&lt;/a&gt; -
Great insights here by &lt;a href="https://mobile.twitter.com/immatthamlin"&gt;Matt Hamlin&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/2018-in-review"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[React Hooks: Array Destructuring Fundamentals]]></title>
<description><![CDATA[This is the first example on the https://reactjs.org/hooks documentation: That const [count, setCount] = useState(0); is the line we're going to be
talking about today. The syntax here is called "array destructuring" and it was
introduced into…]]></description>
<link>https://kentcdodds.com/blog/react-hooks-array-destructuring-fundamentals</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/react-hooks-array-destructuring-fundamentals</guid>
<pubDate>Mon, 31 Dec 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;This is the first example on the &lt;a href="https://reactjs.org/hooks"&gt;https://reactjs.org/hooks&lt;/a&gt; documentation:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;import {useState} from &amp;#x27;react&amp;#x27;
function Example() {
// Declare a new state variable, which we&amp;#x27;ll call &amp;quot;count&amp;quot;
const [count, setCount] = useState(0)
return (
&amp;lt;div&amp;gt;
&amp;lt;p&amp;gt;You clicked {count} times&amp;lt;/p&amp;gt;
&amp;lt;button onClick={() =&amp;gt; setCount(count + 1)}&amp;gt;Click me&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That &lt;code&gt;const [count, setCount] = useState(0);&lt;/code&gt; is the line we&amp;#x27;re going to be
talking about today. The syntax here is called &amp;quot;array destructuring&amp;quot; and it was
introduced into JavaScript in the infamous
(&lt;a href="https://youtu.be/0b6_i_eSgR8"&gt;more than famous&lt;/a&gt;)
&lt;a href="https://github.com/lukehoban/es6features"&gt;ES6 release&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;I&amp;#x27;m a firm believer that:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;a href="https://twitter.com/kentcdodds/status/1074724545003581440"&gt;The better you understand an abstraction, the more effective you will be at using it.&lt;/a&gt;
– me, literally right when I wrote this...&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;So when I see syntax that I&amp;#x27;m unfamiliar with, I like to read about it and
understand how it works with the rest of the language. The problem is that it
can be difficult to &amp;quot;Google&amp;quot; syntax. Seriously... Try Googling the syntax itself
as if you didn&amp;#x27;t know that it&amp;#x27;s called &amp;quot;destructuring.&amp;quot; Pretty tough! So here&amp;#x27;s
my trick. I go to &lt;a href="https://astexplorer.net"&gt;astexplorer.net&lt;/a&gt; and paste in
&lt;a href="https://astexplorer.net/#/gist/c6480f8f68861065fd0f91871540a21f/1dfec03fcab33fb1c4b63e9821c4fc69bcf15973"&gt;the code&lt;/a&gt;
that I don&amp;#x27;t understand:&lt;/p&gt;&lt;p&gt;&lt;img src="https://i.imgur.com/oZGLSfr.png" alt="ASTExplorer.net with the code showing ArrayPattern"/&gt;&lt;/p&gt;&lt;p&gt;Cool! Babel calls that an &amp;quot;ArrayPattern.&amp;quot; So let&amp;#x27;s go ahead and Google for that.
We&amp;#x27;ll search for &amp;quot;site:&lt;a href="https://developer.mozilla.org"&gt;https://developer.mozilla.org&lt;/a&gt; array pattern&amp;quot; (that way
Google only returns results for articles on MDN which is a terrific resource on
learning everything there is to know about JavaScript).&lt;/p&gt;&lt;p&gt;Sweet, the first result takes us to
&lt;a href="https://mdn.io/destructuring"&gt;&amp;quot;Destructuring assignment&amp;quot;&lt;/a&gt; where we can learn
all about this feature (I guess you can read that instead of continuing here if
you want to 😅).&lt;/p&gt;&lt;p&gt;Often syntax like this is what we call &amp;quot;syntactic sugar&amp;quot; for other features.
Here&amp;#x27;s what wikipedia says about
&lt;a href="https://en.wikipedia.org/wiki/Syntactic_sugar"&gt;syntactic sugar&lt;/a&gt;:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;In
&lt;a href="https://en.wikipedia.org/wiki/Computer_science" title="Computer science"&gt;computer science&lt;/a&gt;,
&lt;strong&gt;syntactic sugar&lt;/strong&gt; is syntax within a
&lt;a href="https://en.wikipedia.org/wiki/Programming_language" title="Programming language"&gt;programming language&lt;/a&gt;
that is designed to make things easier to read or to express. It makes the
language &amp;quot;sweeter&amp;quot; for human use: things can be expressed more clearly, more
concisely, or in an alternative style that some may prefer.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Ok, so basically it means that there are common patterns or ways to write code
in a given language, so the language makes a syntax feature to make that pattern
require less code or more expressive. With this in mind, when I&amp;#x27;m learning new
syntax, I like to &amp;quot;de-sugar&amp;quot; the syntax to see what it would look like if we
didn&amp;#x27;t have that feature.&lt;/p&gt;&lt;p&gt;Luckily for us, we have Babel and TypeScript which can compile this newer syntax
into something older browsers can support (and presumably to something we may be
more familiar with). So my next step is to go to
&lt;a href="https://babeljs.io/repl"&gt;the online babel REPL&lt;/a&gt; and paste in the code. Here&amp;#x27;s
what the result looks like:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;&amp;#x27;use strict&amp;#x27;
var _slicedToArray = (function() {
function sliceIterator(arr, i) {
var _arr = []
var _n = true
var _d = false
var _e = undefined
try {
for (
var _i = arr[Symbol.iterator](), _s;
!(_n = (_s = _i.next()).done);
_n = true
) {
_arr.push(_s.value)
if (i &amp;amp;&amp;amp; _arr.length === i) break
}
} catch (err) {
_d = true
_e = err
} finally {
try {
if (!_n &amp;amp;&amp;amp; _i[&amp;#x27;return&amp;#x27;]) _i[&amp;#x27;return&amp;#x27;]()
} finally {
if (_d) throw _e
}
}
return _arr
}
return function(arr, i) {
if (Array.isArray(arr)) {
return arr
} else if (Symbol.iterator in Object(arr)) {
return sliceIterator(arr, i)
} else {
throw new TypeError(
&amp;#x27;Invalid attempt to destructure non-iterable instance&amp;#x27;,
)
}
}
})()
// const [count, setCount] = useState(0);
var _useState = useState(0),
_useState2 = _slicedToArray(_useState, 2),
count = _useState2[0],
setCount = _useState2[1]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;😬 YIKES! Hmmm... Ok, so sometimes Babel uses utilities which both make it more
compliant to the specification, but also can make the code a little harder to
understand. Luckily, there&amp;#x27;s an option on the Babel Repl&amp;#x27;s &amp;quot;Env Preset&amp;quot; called
&amp;quot;Loose&amp;quot; which will simplify this output considerably:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;// const [count, setCount] = useState(0);
var _useState = useState(0),
count = _useState[0],
setCount = _useState[1]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;😌 Phew, that&amp;#x27;s better. Ok, so what&amp;#x27;s going on here. Babel&amp;#x27;s taking our one line
and rather than using the Array Pattern thing, it&amp;#x27;s assigning the return value
of &lt;code&gt;useState&lt;/code&gt; to a variable called &lt;code&gt;_useState&lt;/code&gt;. Then it&amp;#x27;s treating &lt;code&gt;_useState&lt;/code&gt;
as an array and it assigns &lt;code&gt;count&lt;/code&gt; to the first item in the array and &lt;code&gt;setCount&lt;/code&gt;
to the second one.&lt;/p&gt;&lt;p&gt;Let&amp;#x27;s play around with this a little bit to explore the syntax:&lt;/p&gt;&lt;p&gt;Can I call the values whatever I want?&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;// const [whateverIWant, reallyICanChooseWhatItIsCalled] = useState(0);
var _useState = useState(0),
whateverIWant = _useState[0],
reallyICanChooseWhatItIsCalled = _useState[1]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Can I add more elements?&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;// const [count, setCount, somethingElse] = useState(0);
var _useState = useState(0),
count = _useState[0],
setCount = _useState[1],
somethingElse = _useState[2]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Can I pull out fewer?&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;// const [count] = useState(0);
var _useState = useState(0),
count = _useState[0]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Can I skip one?&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;// const [, setCount] = useState(0);
var _useState = useState(0),
setCount = _useState[1]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Can I skip more?&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;// const [,,, wow,, neat] = useState(0);
var _useState = useState(0),
wow = _useState[3],
neat = _useState[5]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I saw someone put a weird &lt;code&gt;=&lt;/code&gt; sign in there, what does that do?&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;// const [count = 3, setCount] = useState(0);
var _useState = useState(0),
_useState$ = _useState[0],
count = _useState$ === undefined ? 3 : _useState$,
setCount = _useState[1]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Oooh, fancy, so if the first element of the array is undefined, then we&amp;#x27;ll set
&lt;code&gt;count&lt;/code&gt; to &lt;code&gt;3&lt;/code&gt; instead. Default values! Sweet.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Note: most of the things above you would never need to do with &lt;code&gt;useState&lt;/code&gt;
because we can always rely on &lt;code&gt;useState&lt;/code&gt; returning an array of two elements!
We&amp;#x27;ll look at that more next.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Ok cool, so this helps us understand what&amp;#x27;s actually going on. There&amp;#x27;s nothing
React-specific about this syntax. It&amp;#x27;s built-into the JavaScript specification,
and React&amp;#x27;s &lt;code&gt;useState&lt;/code&gt; hook is leveraging it as a mechanism for an ergonomic API
that allows you to get two values out of a single function call. Neat!&lt;/p&gt;&lt;p&gt;Ok, so what does &lt;code&gt;useState&lt;/code&gt; actually &lt;em&gt;do&lt;/em&gt; then? What is it really returning? It
must be returning an array for us to be doing the array destructuring like this
right? Cool, let&amp;#x27;s check that out.&lt;/p&gt;&lt;p&gt;One thing that&amp;#x27;s interesting is that the implementation of &lt;code&gt;useState&lt;/code&gt; exists
within &lt;code&gt;react-dom&lt;/code&gt; rather than &lt;code&gt;react&lt;/code&gt;. I know, that may be confusing because we
import &lt;code&gt;useState&lt;/code&gt; from the &lt;code&gt;react&lt;/code&gt; package, but it actually just delegates to
the current renderer (which is &lt;code&gt;react-dom&lt;/code&gt; in our situation here). In fact,
&lt;a href="https://overreacted.io/how-does-setstate-know-what-to-do"&gt;&lt;code&gt;setState&lt;/code&gt; is the same way&lt;/a&gt;!&lt;/p&gt;&lt;p&gt;Another interesting thing about &lt;code&gt;useState&lt;/code&gt; is that the implementation in
&lt;code&gt;react-dom&lt;/code&gt; is just a few lines:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;function useState(initialState) {
return useReducer(
basicStateReducer,
// useReducer has a special case to support lazy useState initializers
initialState,
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;😱 it&amp;#x27;s actually just a hook that&amp;#x27;s using the &lt;code&gt;useReducer&lt;/code&gt; hook! Ok, but what is
that &lt;code&gt;basicStateReducer&lt;/code&gt; thing huh?&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;function basicStateReducer(state, action) {
return typeof action === &amp;#x27;function&amp;#x27; ? action(state) : action
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, interesting, so &lt;code&gt;useReducer&lt;/code&gt; is actually
&lt;a href="https://github.com/facebook/react/blob/f1bf281605444b342f4c37718092accbe3f98702/packages/react-reconciler/src/ReactFiberHooks.js#L471"&gt;over 100 lines of code&lt;/a&gt;,
so let&amp;#x27;s just look at what &lt;code&gt;useReducer&lt;/code&gt;
&lt;a href="https://github.com/facebook/react/blob/f1bf281605444b342f4c37718092accbe3f98702/packages/react-reconciler/src/ReactFiberHooks.js#L383"&gt;returns&lt;/a&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;return [newState, dispatch]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;See! It&amp;#x27;s an array! So when we call &lt;code&gt;useState&lt;/code&gt;, it returns a call to
&lt;code&gt;useReducer&lt;/code&gt; which will return an array of two values. This allows us to do the
array destructuring that we want so instead of writing:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const stateAndUpdater = useState(0)
const count = stateAndUpdater[0]
const setCount = stateAndUpdater[1]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can write:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const [count, setCount] = useState(0)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Nice!&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;I hope you found this one helpful! Even if you already are very familiar with
destructing syntax, the process of learning new syntax I show above has been
helpful to me as recently as Friday when I was playing around with TypeScript.
Seeing syntax that I&amp;#x27;m not familiar with and learning new things is something
that I&amp;#x27;ll never get tired of in this industry! And learning the fundamentals
behind these bits of syntax will make you more effective at using them. I should
mention also that there are more things you can do with destructuring and if
you&amp;#x27;re interested there&amp;#x27;s
&lt;a href="https://youtu.be/t3R3R7UyN2Y?t=1h07m01s&amp;amp;list=PLV5CVI1eNcJgUA2ziIML3-7sMbS7utie5"&gt;a section about destructuring in my ES6 workshop&lt;/a&gt;
that&amp;#x27;s available completely free on
&lt;a href="https://kcd.im/youtube"&gt;my YouTube channel&lt;/a&gt;. Good luck!&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;&lt;strong&gt;Learn more about React from me&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://kcd.im/beginner-react"&gt;The Beginner&amp;#x27;s Guide to React&lt;/a&gt; - Absolute
fundamentals of React&lt;/li&gt;&lt;li&gt;&lt;a href="https://kcd.im/hooks-and-suspense"&gt;React Hooks and Suspense&lt;/a&gt; - A great primer
on Hooks and Suspense&lt;/li&gt;&lt;li&gt;&lt;a href="https://kcd.im/refactor-react"&gt;Simplify React Apps with React Hooks&lt;/a&gt; - Let&amp;#x27;s
take some real-world class components and refactor them to function components
with hooks.&lt;/li&gt;&lt;li&gt;&lt;a href="https://kcd.im/advanced-react"&gt;Advanced React Component Patterns&lt;/a&gt; - Amazing
patterns to make your components more reusable, flexible, and simple all at
once. (Also on
&lt;a href="https://frontendmasters.com/courses/advanced-react-patterns"&gt;Frontend Masters&lt;/a&gt;).&lt;/li&gt;&lt;li&gt;&lt;a href="https://kcd.im/youtube"&gt;My YouTube channel&lt;/a&gt; is also full of content about
&lt;a href="https://youtube.com/user/kentdoddsfamily/search?query=react"&gt;React&lt;/a&gt; that
you&amp;#x27;d probably enjoy (including
&lt;a href="https://youtube.com/playlist?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;workshops, talks&lt;/a&gt;,
and &lt;a href="https://kcd.im/devtips"&gt;livestreams&lt;/a&gt;).&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://devhubapp.com"&gt;DevHub&lt;/a&gt; - TweetDeck for GitHub by
&lt;a href="https://twitter.com/brunolemos"&gt;Bruno Lemos&lt;/a&gt;. The project itself is
&lt;a href="https://github.com/devhubapp/devhub"&gt;open source&lt;/a&gt; and pretty impressive. It&amp;#x27;s
&lt;a href="https://twitter.com/brunolemos/status/1072871009651384320"&gt;&amp;quot;a production app using React Hooks, React Native Web with a 95%+ code sharing between web and mobile, CRA, TypeScript, Yarn Workspaces and Redux&amp;quot;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.modernjsbyexample.net"&gt;Modern Javascript by Example&lt;/a&gt; - A free
(donations welcome) open source book by
&lt;a href="https://twitter.com/MrBenJ5"&gt;Ben Junya&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.byteconf.com/blog/what-i-use-kent-c-dodds"&gt;What I Use: Kent C. Dodds&lt;/a&gt; -
&lt;a href="https://twitter.com/byteconf"&gt;Byteconf&lt;/a&gt; is starting something new by talking
to their favorite folks in the software dev world to find out how they do
their best work. I was the first one!&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/react-hooks-array-destructuring-fundamentals"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[React Hooks: What's going to happen to my tests?]]></title>
<description><![CDATA[Current Available Translations: Korean One of the most common questions I hear about the upcoming React Hooks feature
is regarding testing. And I can understand the concern when your tests look like
this: That enzyme test works when Accordion is a…]]></description>
<link>https://kentcdodds.com/blog/react-hooks-whats-going-to-happen-to-my-tests</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/react-hooks-whats-going-to-happen-to-my-tests</guid>
<pubDate>Mon, 24 Dec 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;Current Available Translations:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://edykim.com/ko/post/react-hooks-whats-going-to-happen-to-my-tests"&gt;Korean&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;One of the most common questions I hear about the upcoming React Hooks feature
is regarding testing. And I can understand the concern when your tests look like
this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;// borrowed from a previous blog post:
// https://kcd.im/implementation-details
test(&amp;#x27;setOpenIndex sets the open index state properly&amp;#x27;, () =&amp;gt; {
const wrapper = mount(&amp;lt;Accordion items={[]} /&amp;gt;)
expect(wrapper.state(&amp;#x27;openIndex&amp;#x27;)).toBe(0)
wrapper.instance().setOpenIndex(1)
expect(wrapper.state(&amp;#x27;openIndex&amp;#x27;)).toBe(1)
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That enzyme test works when &lt;code&gt;Accordion&lt;/code&gt; is a class component where the
&lt;code&gt;instance&lt;/code&gt; actually exists, but there&amp;#x27;s no concept of a component &amp;quot;instance&amp;quot;
when your components are function components. So doing things like &lt;code&gt;.instance()&lt;/code&gt;
or &lt;code&gt;.state()&lt;/code&gt; wont work when you refactor your components from class components
with state/lifecycles to function components with hooks.&lt;/p&gt;&lt;p&gt;So if you were to refactor the &lt;code&gt;Accordion&lt;/code&gt; component to a function component,
those tests would break. So what can we do to make sure that our codebase is
ready for hooks refactoring without having to either throw away our tests or
rewrite them? You can start by avoiding enzyme APIs that reference the component
instance like the test above. You can read more about this in
&lt;a href="https://kcd.im/imp-deets"&gt;my &amp;quot;implementation details&amp;quot; blog post&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Let&amp;#x27;s look at a simpler example of a class component. My favorite example is a
&lt;code&gt;&amp;lt;Counter /&amp;gt;&lt;/code&gt; component:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;// counter.js
import React from &amp;#x27;react&amp;#x27;
class Counter extends React.Component {
state = {count: 0}
increment = () =&amp;gt; this.setState(({count}) =&amp;gt; ({count: count + 1}))
render() {
return &amp;lt;button onClick={this.increment}&amp;gt;{this.state.count}&amp;lt;/button&amp;gt;
}
}
export default Counter
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now let&amp;#x27;s see how we could test it in a way that&amp;#x27;s ready for refactoring it to
use hooks:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;// __tests__/counter.js
import React from &amp;#x27;react&amp;#x27;
import &amp;#x27;react-testing-library/cleanup-after-each&amp;#x27;
import {render, fireEvent} from &amp;#x27;react-testing-library&amp;#x27;
import Counter from &amp;#x27;../counter.js&amp;#x27;
test(&amp;#x27;counter increments the count&amp;#x27;, () =&amp;gt; {
const {container} = render(&amp;lt;Counter /&amp;gt;)
const button = container.firstChild
expect(button.textContent).toBe(&amp;#x27;0&amp;#x27;)
fireEvent.click(button)
expect(button.textContent).toBe(&amp;#x27;1&amp;#x27;)
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That test will pass. Now, let&amp;#x27;s refactor this to a hooks version of the same
component:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;// counter.js
import React from &amp;#x27;react&amp;#x27;
function Counter() {
const [count, setCount] = useState(0)
const incrementCount = () =&amp;gt; setCount(c =&amp;gt; c + 1)
return &amp;lt;button onClick={incrementCount}&amp;gt;{count}&amp;lt;/button&amp;gt;
}
export default Counter
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Guess what! Because our tests avoided implementation details, our hooks are
passing! How neat is that!? :)&lt;/p&gt;&lt;h3&gt;useEffect is not componentDidMount + componentDidUpdate + componentWillUnmount&lt;/h3&gt;&lt;p&gt;Another thing to consider is the &lt;code&gt;useEffect&lt;/code&gt; hook because it actually is a
little unique/special/different/awesome. When you&amp;#x27;re refactoring from class
components to hooks, you&amp;#x27;ll typically move the logic from &lt;code&gt;componentDidMount&lt;/code&gt;,
&lt;code&gt;componentDidUpdate&lt;/code&gt;, and &lt;code&gt;componentWillUnmount&lt;/code&gt;to one or more &lt;code&gt;useEffect&lt;/code&gt;
callbacks (depending on the number of concerns your component has in those
lifecycles). But this is actually &lt;em&gt;not&lt;/em&gt; a refactor. Let&amp;#x27;s get a quick review of
what a &amp;quot;refactor&amp;quot; actually is.&lt;/p&gt;&lt;p&gt;When you refactor code, you&amp;#x27;re making changes to the implementation without
making user-observable changes.
&lt;a href="https://en.wikipedia.org/wiki/Code_refactoring"&gt;Here&amp;#x27;s what wikipedia says about &amp;quot;code refactoring&amp;quot;&lt;/a&gt;:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Code refactoring&lt;/strong&gt; is the process of restructuring existing computer
code — changing the
&lt;a href="https://en.wikipedia.org/wiki/Decomposition_%28computer_science%29" title="Decomposition (computer science)"&gt;factoring&lt;/a&gt;
 without changing its external behavior.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Ok, let&amp;#x27;s try that idea out with an example:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;const sum = (a, b) =&amp;gt; a + b
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here&amp;#x27;s a refactor of this function:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;const sum = (a, b) =&amp;gt; b + a
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It still works exactly the same, but the implementation itself is a little
different. Fundamentally that&amp;#x27;s what a &amp;quot;refactor&amp;quot; is. Ok, now, here&amp;#x27;s what a
refactor is &lt;em&gt;not&lt;/em&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;const sum = (...args) =&amp;gt; args.reduce((s, n) =&amp;gt; s + n, 0)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is awesome, our &lt;code&gt;sum&lt;/code&gt; is more capable, but what we did was &lt;em&gt;not&lt;/em&gt;
technically a refactor, it was an enhancement. Let&amp;#x27;s compare:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;| call | result before | result after |
|--------------|---------------|--------------|
| sum() | NaN | 0 |
| sum(1) | NaN | 1 |
| sum(1, 2) | 3 | 3 |
| sum(1, 2, 3) | 3 | 6 |
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So why was this not a refactor? It&amp;#x27;s because we are &amp;quot;changing its external
behavior.&amp;quot; Now, this change is desirable, but it is a change.&lt;/p&gt;&lt;p&gt;So what does all this have to do with &lt;code&gt;useEffect&lt;/code&gt;? Let&amp;#x27;s look at another example
of our counter component as a class with a new feature:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;class Counter extends React.Component {
state = {
count: Number(window.localStorage.getItem(&amp;#x27;count&amp;#x27;) || 0),
}
increment = () =&amp;gt; this.setState(({count}) =&amp;gt; ({count: count + 1}))
componentDidMount() {
window.localStorage.setItem(&amp;#x27;count&amp;#x27;, this.state.count)
}
componentDidUpdate(prevProps, prevState) {
if (prevState.count !== this.state.count) {
window.localStorage.setItem(&amp;#x27;count&amp;#x27;, this.state.count)
}
}
render() {
return &amp;lt;button onClick={this.increment}&amp;gt;{this.state.count}&amp;lt;/button&amp;gt;
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, so we&amp;#x27;re saving the value of &lt;code&gt;count&lt;/code&gt; in &lt;code&gt;localStorage&lt;/code&gt; using
&lt;code&gt;componentDidMount&lt;/code&gt; and &lt;code&gt;componentDidUpdate&lt;/code&gt;. Here&amp;#x27;s what our
implementation-details-free test would look like:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;// __tests__/counter.js
import React from &amp;#x27;react&amp;#x27;
import &amp;#x27;react-testing-library/cleanup-after-each&amp;#x27;
import {render, fireEvent, cleanup} from &amp;#x27;react-testing-library&amp;#x27;
import Counter from &amp;#x27;../counter.js&amp;#x27;
afterEach(() =&amp;gt; {
window.localStorage.removeItem(&amp;#x27;count&amp;#x27;)
})
test(&amp;#x27;counter increments the count&amp;#x27;, () =&amp;gt; {
const {container} = render(&amp;lt;Counter /&amp;gt;)
const button = container.firstChild
expect(button.textContent).toBe(&amp;#x27;0&amp;#x27;)
fireEvent.click(button)
expect(button.textContent).toBe(&amp;#x27;1&amp;#x27;)
})
test(&amp;#x27;reads and updates localStorage&amp;#x27;, () =&amp;gt; {
window.localStorage.setItem(&amp;#x27;count&amp;#x27;, 3)
const {container, rerender} = render(&amp;lt;Counter /&amp;gt;)
const button = container.firstChild
expect(button.textContent).toBe(&amp;#x27;3&amp;#x27;)
fireEvent.click(button)
expect(button.textContent).toBe(&amp;#x27;4&amp;#x27;)
expect(window.localStorage.getItem(&amp;#x27;count&amp;#x27;)).toBe(&amp;#x27;4&amp;#x27;)
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That test passes! Woo! Now let&amp;#x27;s &amp;quot;refactor&amp;quot; this to hooks again with these new
features:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;import React, {useState, useEffect} from &amp;#x27;react&amp;#x27;
function Counter() {
const [count, setCount] = useState(() =&amp;gt;
Number(window.localStorage.getItem(&amp;#x27;count&amp;#x27;) || 0),
)
const incrementCount = () =&amp;gt; setCount(c =&amp;gt; c + 1)
useEffect(() =&amp;gt; {
window.localStorage.setItem(&amp;#x27;count&amp;#x27;, count)
}, [count])
return &amp;lt;button onClick={incrementCount}&amp;gt;{count}&amp;lt;/button&amp;gt;
}
export default Counter
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Cool, as far as the user is concerned, this component will work &lt;em&gt;exactly&lt;/em&gt; the
same as it had before. But it&amp;#x27;s actually working differently from how it was
before. The real trick here is that &lt;strong&gt;the&lt;/strong&gt; &lt;code&gt;**useEffect**&lt;/code&gt; &lt;strong&gt;callback is
&lt;em&gt;scheduled&lt;/em&gt; to run at a later time&lt;/strong&gt;. So before, we set the value of
&lt;code&gt;localStorage&lt;/code&gt; synchronously after rendering. Now, it&amp;#x27;s scheduled to run later
after rendering. Why is this? Let&amp;#x27;s checkout
&lt;a href="https://reactjs.org/docs/hooks-effect.html#detailed-explanation"&gt;this tip from the React Hooks docs&lt;/a&gt;:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Unlike &lt;code&gt;componentDidMount&lt;/code&gt; or &lt;code&gt;componentDidUpdate&lt;/code&gt;, effects scheduled with
&lt;code&gt;useEffect&lt;/code&gt; don&amp;#x27;t block the browser from updating the screen. This makes your
app feel more responsive. The majority of effects don&amp;#x27;t need to happen
synchronously. In the uncommon cases where they do (such as measuring the
layout), there is a separate
&lt;a href="https://reactjs.org/docs/hooks-reference.html#uselayouteffect"&gt;&lt;code&gt;useLayoutEffect&lt;/code&gt;&lt;/a&gt;
Hook with an API identical to &lt;code&gt;useEffect&lt;/code&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Ok, so by using &lt;code&gt;useEffect&lt;/code&gt; that&amp;#x27;s better for performance! Awesome! We&amp;#x27;ve made
an enhancement to our component and our component code is actually simpler to
boot! NEAT!&lt;/p&gt;&lt;p&gt;However, this is &lt;em&gt;not&lt;/em&gt; a refactor. It&amp;#x27;s actually a change in behavior. As far as
the &lt;em&gt;end&lt;/em&gt; user is concerned, that change is unobservable. In our efforts to
ensure that our tests are free of implementation details, that change should be
unobservable as well.&lt;/p&gt;&lt;p&gt;Whelp, thanks to the new &lt;a href="https://reactjs.org/docs/test-utils.html#act"&gt;&lt;code&gt;act&lt;/code&gt;&lt;/a&gt;
utility from &lt;a href="https://reactjs.org/docs/test-utils.html"&gt;&lt;code&gt;react-dom/test-utils&lt;/code&gt;&lt;/a&gt;
we can make that happen. So &lt;code&gt;react-testing-library&lt;/code&gt; integrates with that utility
and makes it so all our tests continue to pass as written, allowing the tests we
write to be free of implementation details and continue to resemble the way our
software is used as closely as possible.&lt;/p&gt;&lt;h3&gt;What about render props components?&lt;/h3&gt;&lt;p&gt;This is probably my favorite actually. Here&amp;#x27;s a simple counter render prop
component:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;class Counter extends React.Component {
state = {count: 0}
increment = () =&amp;gt; this.setState(({count}) =&amp;gt; ({count: count + 1}))
render() {
return this.props.children({
count: this.state.count,
increment: this.increment,
})
}
}
// usage:
// &amp;lt;Counter&amp;gt;
// {({ count, increment }) =&amp;gt; &amp;lt;button onClick={increment}&amp;gt;{count}&amp;lt;/button&amp;gt;}
// &amp;lt;/Counter&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here&amp;#x27;s how I would test this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;// __tests__/counter.js
import React from &amp;#x27;react&amp;#x27;
import &amp;#x27;react-testing-library/cleanup-after-each&amp;#x27;
import {render, fireEvent} from &amp;#x27;react-testing-library&amp;#x27;
import Counter from &amp;#x27;../counter.js&amp;#x27;
function renderCounter(props) {
let utils
const children = jest.fn(stateAndHelpers =&amp;gt; {
utils = stateAndHelpers
return null
})
return {
...render(&amp;lt;Counter {...props}&amp;gt;{children}&amp;lt;/Counter&amp;gt;),
children,
// this will give us access to increment and count
...utils,
}
}
test(&amp;#x27;counter increments the count&amp;#x27;, () =&amp;gt; {
const {children, increment} = renderCounter()
expect(children).toHaveBeenCalledWith(expect.objectContaining({count: 0}))
increment()
expect(children).toHaveBeenCalledWith(expect.objectContaining({count: 1}))
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, so let&amp;#x27;s refactor the counter to a component that uses hooks:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;function Counter(props) {
const [count, setCount] = useState(0)
const increment = () =&amp;gt; setCount(currentCount =&amp;gt; currentCount + 1)
return props.children({
count: count,
increment,
})
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Cool, and because we wrote our test the way we did, it&amp;#x27;s actually still passing.
Woo! BUT! As we learned from
&amp;quot;&lt;a href="https://kentcdodds.com/blog/react-hooks-whats-going-to-happen-to-render-props"&gt;React Hooks: What&amp;#x27;s going to happen to render props?&lt;/a&gt;&amp;quot;
custom hooks are a better primitive for code sharing in React. So let&amp;#x27;s rewrite
this to a custom hook:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;function useCounter() {
const [count, setCount] = useState(0)
const increment = () =&amp;gt; setCount(currentCount =&amp;gt; currentCount + 1)
return {count, increment}
}
export default useCounter
// usage:
// function Counter() {
// const {count, increment} = useCounter()
// return &amp;lt;button onClick={increment}&amp;gt;{count}&amp;lt;/button&amp;gt;
// }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Awesome... but how do we test &lt;code&gt;useCounter&lt;/code&gt;? And wait! We can&amp;#x27;t update our entire
codebase to the new &lt;code&gt;useCounter&lt;/code&gt;! We were using the &lt;code&gt;&amp;lt;Counter /&amp;gt;&lt;/code&gt; render prop
based component in like three hundred places!? Rewrites are the worst!&lt;/p&gt;&lt;p&gt;Nah, I got you. Do this instead:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;function useCounter() {
const [count, setCount] = useState(0)
const increment = () =&amp;gt; setCount(currentCount =&amp;gt; currentCount + 1)
return {count, increment}
}
const Counter = ({children, ...props}) =&amp;gt; children(useCounter(props))
export default Counter
export {useCounter}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Our new &lt;code&gt;&amp;lt;Counter /&amp;gt;&lt;/code&gt; render-prop based component there is actually &lt;em&gt;exactly&lt;/em&gt;
the same as the one we had before. So this is a true refactor. But now anyone
who can take the time to upgrade can use our &lt;code&gt;useCounter&lt;/code&gt;custom hook.&lt;/p&gt;&lt;p&gt;Oh, and guess what. Our tests are still passing!!! WHAT! How neat right?&lt;/p&gt;&lt;p&gt;So when everyone&amp;#x27;s upgraded we can remove the Counter function component right?
You may be able to do that, but I would actually move it to the &lt;code&gt;__tests__&lt;/code&gt;
because &lt;em&gt;that&amp;#x27;s&lt;/em&gt; how I like testing custom hooks! I prefer making a render-prop
based component out of a custom hook, and actually rendering that and asserting
on what the function is called with.&lt;/p&gt;&lt;p&gt;Fun trick right? I show you how to do this in
&lt;a href="https://kcd.im/refactor-react"&gt;my new course on egghead.io&lt;/a&gt;. Enjoy!&lt;/p&gt;&lt;h2&gt;What about hooks libraries?&lt;/h2&gt;&lt;p&gt;If you&amp;#x27;re writing a generic or open source hook, then you may want to test it
without a specific component in mind. In that case, I recommend using
&lt;a href="https://www.npmjs.com/package/react-hooks-testing-library"&gt;&lt;code&gt;react-hooks-testing-library&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;One of the best things you can do before you refactor code is have a good test
suite/type definitions in place so when you inadvertently break something you
can be made aware of the mistake right away. But &lt;strong&gt;your test suite can&amp;#x27;t do you
any good if you have to throw it away when you refactor it.&lt;/strong&gt; Take my advice:
&lt;a href="https://kcd.im/imp-deets"&gt;avoid implementation details&lt;/a&gt; in your tests. Write
tests that will work today with classes, and in the future if those classes are
refactored to functions with hooks. Good luck!&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Learn more about React Hooks from me&lt;/strong&gt;:&lt;/p&gt;&lt;p&gt;If you thought this was interesting, I highly recommend you watch these (while
they&amp;#x27;re both still free):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://kcd.im/hooks-and-suspense"&gt;React Hooks and Suspense&lt;/a&gt;  —  A great
primer on Hooks and Suspense&lt;/li&gt;&lt;li&gt;&lt;a href="http://kcd.im/refactor-react"&gt;Simplify React Apps with React Hooks&lt;/a&gt;  — Let&amp;#x27;s
take some real-world class components and refactor them to function components
with hooks.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://github.com/rescripts/rescripts"&gt;rescripts&lt;/a&gt;  —  💥 Use the latest
react-scripts with custom configurations for Babel, ESLint, TSLint,
Webpack,... ∞ by &lt;a href="https://twitter.com/hsolvz"&gt;Harry Solovay&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/k6KcaMffxac?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;Contributing to Open Source on GitHub for beginners&lt;/a&gt; 
—  A talk I gave at my Alma mater (BYU) this last week&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/HL6paXyx6hM?list=PLV5CVI1eNcJgCrPH_e6d57KRUTiDZgs0u"&gt;Make a SUPER simple personal URL shortener with Netlify&lt;/a&gt;
(I&amp;#x27;m still livestreaming almost every week day at
&lt;a href="https://kcd.im/devtips"&gt;kcd.im/devtips&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;&lt;a href="https://twitter.com/jamiebuilds/status/1022568918949408768"&gt;The three browsers holding JavaScript back the most are:&lt;/a&gt;...
An interesting thread by &lt;a href="https://twitter.com/jamiebuilds"&gt;Jamie Kyle&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;a href="https://medium.com/emotion-js/announcing-emotion-10-f1a4b17b8ccd"&gt;Emotion 10 released!&lt;/a&gt; 
—  This is still my favorite CSS-in-JS solution and
&lt;a href="https://twitter.com/tkh44/status/1070901663622283265"&gt;this is why&lt;/a&gt; I prefer
it over styled-components.&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/react-hooks-whats-going-to-happen-to-my-tests"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[React Hooks: What's going to happen to react context?]]></title>
<description><![CDATA[Earlier this year, the React team introduced the first official context API.
I blogged about that new API and people got
sufficiently and reasonably hyped. One common complaint that I knew people were going to have when applying it
practically was…]]></description>
<link>https://kentcdodds.com/blog/react-hooks-whats-going-to-happen-to-react-context</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/react-hooks-whats-going-to-happen-to-react-context</guid>
<pubDate>Mon, 17 Dec 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;Earlier this year, the React team introduced the first official context API.
&lt;a href="https://kentcdodds.com/blog/reacts-new-context-api"&gt;I blogged about that new API&lt;/a&gt; and people got
sufficiently and reasonably hyped.&lt;/p&gt;&lt;p&gt;One common complaint that I knew people were going to have when applying it
practically was the fact that the context consumer is a render-prop based API.
This can lead to a lot of nesting when you need to consume multiple contexts and
other render-prop based APIs as well (for logic reuse). So I addressed that in
the blog post by suggesting that you could combine all of the render-prop based
APIs into a single function component and consume that:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;const ThemeContext = React.createContext(&amp;#x27;light&amp;#x27;)
class ThemeProvider extends React.Component {
/* code */
}
const ThemeConsumer = ThemeContext.Consumer
const LanguageContext = React.createContext(&amp;#x27;en&amp;#x27;)
class LanguageProvider extends React.Component {
/* code */
}
const LanguageConsumer = LanguageContext.Consumer
function AppProviders({children}) {
return (
&amp;lt;LanguageProvider&amp;gt;
&amp;lt;ThemeProvider&amp;gt;{children}&amp;lt;/ThemeProvider&amp;gt;
&amp;lt;/LanguageProvider&amp;gt;
)
}
function ThemeAndLanguageConsumer({children}) {
return (
&amp;lt;LanguageConsumer&amp;gt;
{language =&amp;gt; (
&amp;lt;ThemeConsumer&amp;gt;{theme =&amp;gt; children({language, theme})}&amp;lt;/ThemeConsumer&amp;gt;
)}
&amp;lt;/LanguageConsumer&amp;gt;
)
}
function App() {
return (
&amp;lt;AppProviders&amp;gt;
&amp;lt;ThemeAndLanguageConsumer&amp;gt;
{({theme, language}) =&amp;gt; (
&amp;lt;div&amp;gt;
{theme} and {language}
&amp;lt;/div&amp;gt;
)}
&amp;lt;/ThemeAndLanguageConsumer&amp;gt;
&amp;lt;/AppProviders&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As much as this solution works thanks to the composability of React components,
I&amp;#x27;m still not super thrilled with it. And I&amp;#x27;m not the only one:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;We&amp;#x27;ve heard feedback that adopting the new render prop API can be difficult
in class components. So we&amp;#x27;ve added a convenience API to&lt;/em&gt; &amp;gt;
&lt;a href="https://reactjs.org/docs/context.html#classcontexttype"&gt;&lt;em&gt;consume a context value from within a class component&lt;/em&gt;&lt;/a&gt;&lt;em&gt;. — &lt;/em&gt;&lt;a href="https://reactjs.org/blog/2018/10/23/react-v-16-6.html"&gt;&lt;em&gt;React v16.6.0: lazy, memo and contextType&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;This new convenience API means that if you use a class component and you&amp;#x27;re only
consuming one context, you can simply define a static property called
&lt;code&gt;contextType&lt;/code&gt; and assign it to the context you want to consume, then you can
access the context via &lt;code&gt;this.context&lt;/code&gt;. It&amp;#x27;s pretty neat and a nice trick for
common cases where you only consume a single context.&lt;/p&gt;&lt;p&gt;I&amp;#x27;ve used this convenience API and I love it. But I&amp;#x27;m even more excited about
the implications that React Hooks have for the future of React context. Let&amp;#x27;s
rewrite what we have above with the upcoming (ALPHA!) &lt;code&gt;useContext&lt;/code&gt; hook:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;const ThemeContext = React.createContext(&amp;#x27;light&amp;#x27;)
class ThemeProvider extends React.Component {
/* code */
}
const LanguageContext = React.createContext(&amp;#x27;en&amp;#x27;)
class LanguageProvider extends React.Component {
/* code */
}
function AppProviders({children}) {
return (
&amp;lt;LanguageProvider&amp;gt;
&amp;lt;ThemeProvider&amp;gt;{children}&amp;lt;/ThemeProvider&amp;gt;
&amp;lt;/LanguageProvider&amp;gt;
)
}
function App() {
const theme = useContext(ThemeContext)
const language = useContext(LanguageContext)
return (
&amp;lt;div&amp;gt;
{theme} and {language}
&amp;lt;/div&amp;gt;
)
}
ReactDOM.render(
&amp;lt;AppProviders&amp;gt;
&amp;lt;App /&amp;gt;
&amp;lt;/AppProviders&amp;gt;,
document.getElementById(&amp;#x27;root&amp;#x27;),
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;WOWZA! As powerful as the render-prop based consumers are, this is even easier
to read, understand, refactor, and maintain! And it&amp;#x27;s not just less code for
less code&amp;#x27;s sake. Besides, often when we reduce the amount of code we also
reduce the clarity of communication that code can give to us. But in this case,
it&amp;#x27;s less code &lt;em&gt;and&lt;/em&gt; it&amp;#x27;s easier to understand. I think that&amp;#x27;s a big win and a
huge feature of the new hooks API.&lt;/p&gt;&lt;p&gt;Another big feature of React hooks is the fact that it&amp;#x27;s completely opt-in and
backward compatible. I&amp;#x27;m given such a huge amount of comfort knowing that
Facebook can&amp;#x27;t make decisions that will cause grief to the engineers who are
working on &lt;em&gt;the&lt;/em&gt; oldest and one of the largest React codebases in the world. The
fact that React has incrementally taken us to this new world of hooks is just
fantastic. Thanks React team! Looking forward to the official release!&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;One of the coolest things about React is that it allows us to focus on solving
real-world problems without normally having to get too close to the
implementation of things. It&amp;#x27;s been a long time since I had to deal with
cross-browser or performance issues with any degree of regularity. And now React
is taking it even further and simplifying things so the code that I do write is
simpler to read, understand refactor, and maintain. I just love that. Makes me
wonder if there may be some things I could do about my code to simplify things
for other people as well 🤔.&lt;/p&gt;&lt;p&gt;Until next time! Good luck! 👋&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://kcd.im/refactor-react"&gt;Simplify React Apps with React Hooks and Suspense&lt;/a&gt; — My
new egghead course... of course!&lt;/li&gt;&lt;li&gt;&lt;a href="http://kcd.im/shurlan"&gt;Shurlan&lt;/a&gt; — I WON &lt;a href="https://nanowrimo.org"&gt;NANOWRIMO&lt;/a&gt;
THIS YEAR! That means that I successfully wrote 50,000 words of a novel in the
month of November (for perspective, Harry Potter book 1 is 76k words). It was
a wild month, and it was tons of fun. And you can read what I ended up with.
It&amp;#x27;s a fantasy novel about a utopian world where things start to go bad and a
14-year-old girl is tasked with stopping a rebellion from inadvertently
destroying the city. I think you&amp;#x27;ll love the characters, plot, and magic
system :)&lt;/li&gt;&lt;li&gt;&lt;a href="https://reactjs.org/blog/2018/11/27/react-16-roadmap.html"&gt;React 16.x Roadmap&lt;/a&gt; — Tl;DR:
React 16.6: Suspense for Code Splitting (already shipped), React 16.7: React
Hooks (~Q1 2019), React 16.8: Concurrent Mode (~Q2 2019), React 16.9: Suspense
for Data Fetching (~mid 2019)&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/xcZXS_VEJS0?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;Modern React Workshop: Hooks &amp;amp; Suspense&lt;/a&gt; — a
recording of a livestream I did last week at PayPal.
&lt;a href="https://github.com/kentcdodds/modern-react"&gt;Here&amp;#x27;s the workshop repo&lt;/a&gt; and
&lt;a href="https://youtu.be/NKAfuguroRY?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;here&amp;#x27;s the part 2&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/react-hooks-whats-going-to-happen-to-react-context"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[React Hooks: What's going to happen to render props?]]></title>
<description><![CDATA[Current Available Translations: Korean About a year ago, I published
"How to give rendering control to users with prop getters" .
In that post, I show the entire implementation (at the time) of
react-toggled which I actually
built for the sole…]]></description>
<link>https://kentcdodds.com/blog/react-hooks-whats-going-to-happen-to-render-props</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/react-hooks-whats-going-to-happen-to-render-props</guid>
<pubDate>Mon, 10 Dec 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;Current Available Translations:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://edykim.com/ko/post/react-hooks-whats-going-to-happen-to-render-props"&gt;Korean&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;About a year ago, I published
&lt;a href="https://kentcdodds.com/blog/how-to-give-rendering-control-to-users-with-prop-getters"&gt;&amp;quot;How to give rendering control to users with prop getters&amp;quot;&lt;/a&gt;.
In that post, I show the entire implementation (at the time) of
&lt;a href="https://github.com/kentcdodds/react-toggled"&gt;&lt;code&gt;react-toggled&lt;/code&gt;&lt;/a&gt; which I actually
built for the sole purpose of teaching some of the patterns that I used in
&lt;a href="https://github.com/downshift-js/downshift"&gt;&lt;code&gt;downshift&lt;/code&gt;&lt;/a&gt;. It&amp;#x27;s a much smaller
and simpler component that implements many of the same patterns as downshift so
it served as a great way to teach the prop getters pattern.&lt;/p&gt;&lt;p&gt;Both react-toggled and downshift use the render prop pattern as a mechanism for
React component logic code sharing. As I explained in my blog post
&lt;a href="https://kentcdodds.com/blog/when-to-not-use-render-props"&gt;&amp;quot;When to NOT use Render Props&amp;quot;&lt;/a&gt;, that&amp;#x27;s the
primary use case for the render prop pattern. But that&amp;#x27;s also the primary use
case for React Hooks as well. And React Hooks are WAY simpler than class
components + render props.&lt;/p&gt;&lt;p&gt;So does that mean that when React Hooks are stable you wont need render props at
all anymore? &lt;strong&gt;No!&lt;/strong&gt; I can think of two scenarios where the render prop pattern
will still be very useful, and I&amp;#x27;ll share those with you in a moment. But let&amp;#x27;s
go ahead and establish my claim that hooks are simpler by comparing the current
version of &lt;code&gt;react-toggled&lt;/code&gt; with a hooks-based implementation.&lt;/p&gt;&lt;p&gt;If you&amp;#x27;re interested,
&lt;a href="https://github.com/kentcdodds/react-toggled/blob/8452a1f2a4ec7b64588cd8c9812e0faf8deb0271/src/index.js"&gt;here&amp;#x27;s the current source for&lt;/a&gt;
&lt;a href="https://github.com/kentcdodds/react-toggled/blob/8452a1f2a4ec7b64588cd8c9812e0faf8deb0271/src/index.js"&gt;&lt;code&gt;react-toggled&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Here&amp;#x27;s a typical usage of &lt;code&gt;react-toggled&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;function App() {
return (
&amp;lt;Toggle&amp;gt;
{({on, toggle}) =&amp;gt; &amp;lt;button onClick={toggle}&amp;gt;{on ? &amp;#x27;on&amp;#x27; : &amp;#x27;off&amp;#x27;}&amp;lt;/button&amp;gt;}
&amp;lt;/Toggle&amp;gt;
)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If all we wanted was simple toggle functionality, our hook version would be:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;function useToggle(initialOn = false) {
const [on, setOn] = useState(initialOn)
const toggle = () =&amp;gt; setOn(!on)
return {on, toggle}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then people could use that like so:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;function App() {
const {on, toggle} = useToggle()
return &amp;lt;button onClick={toggle}&amp;gt;{on ? &amp;#x27;on&amp;#x27; : &amp;#x27;off&amp;#x27;}&amp;lt;/button&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Cool! A lot simpler! But the Toggle component in react-toggled actually supports
a lot more. For one thing, it provides a helper called &lt;code&gt;getTogglerProps&lt;/code&gt; which
will give you the correct props you need for a toggler to work (including
&lt;code&gt;aria&lt;/code&gt;attributes for accessibility). So let&amp;#x27;s make that work:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;// returns a function which calls all the given functions
const callAll = (...fns) =&amp;gt; (...args) =&amp;gt; fns.forEach(fn =&amp;gt; fn &amp;amp;&amp;amp; fn(...args))
function useToggle(initialOn = false) {
const [on, setOn] = useState(initialOn)
const toggle = () =&amp;gt; setOn(!on)
const getTogglerProps = (props = {}) =&amp;gt; ({
&amp;#x27;aria-expanded&amp;#x27;: on,
tabIndex: 0,
...props,
onClick: callAll(props.onClick, toggle),
})
return {
on,
toggle,
getTogglerProps,
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And now our &lt;code&gt;useToggle&lt;/code&gt; hook can use the &lt;code&gt;getTogglerProps&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;function App() {
const {on, getTogglerProps} = useToggle()
return &amp;lt;button {...getTogglerProps()}&amp;gt;{on ? &amp;#x27;on&amp;#x27; : &amp;#x27;off&amp;#x27;}&amp;lt;/button&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And it&amp;#x27;s more accessible and stuff. Neat right? Well, what if I don&amp;#x27;t need the
&lt;code&gt;getTogglerProps&lt;/code&gt; for my use case? Let&amp;#x27;s split this up a bit:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;// returns a function which calls all the given functions
const callAll = (...fns) =&amp;gt; (...args) =&amp;gt; fns.forEach(fn =&amp;gt; fn &amp;amp;&amp;amp; fn(...args))
function useToggle(initialOn = false) {
const [on, setOn] = useState(initialOn)
const toggle = () =&amp;gt; setOn(!on)
return {on, toggle}
}
function useToggleWithPropGetter(initialOn) {
const {on, toggle} = useToggle(initialOn)
const getTogglerProps = (props = {}) =&amp;gt; ({
&amp;#x27;aria-expanded&amp;#x27;: on,
tabIndex: 0,
...props,
onClick: callAll(props.onClick, toggle),
})
return {on, toggle, getTogglerProps}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And we could do the same thing to support the &lt;code&gt;getInputTogglerProps&lt;/code&gt; and
&lt;code&gt;getElementTogglerProps&lt;/code&gt; helpers that &lt;code&gt;react-toggled&lt;/code&gt; currently supports. This
would actually allow us to easily tree-shake out those extra utilities that our
app is not using, something that would be pretty unergonomic to do with a render
props solution (not impossible, just kinda ugly).&lt;/p&gt;&lt;p&gt;&lt;strong&gt;But Kent!&lt;/strong&gt; I don&amp;#x27;t want to go and refactor all the places in my app that use
the render prop API to use the new hooks API!!&lt;/p&gt;&lt;p&gt;Never fear! Check this out:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;const Toggle = ({children, ...props}) =&amp;gt; children(useToggle(props))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There&amp;#x27;s your render prop component. You can use that just like you were using
the old one and migrate over time. In fact, this is how I recommend testing
custom hooks!&lt;/p&gt;&lt;p&gt;There&amp;#x27;s a little more to this (like how do we port the control props pattern to
react hooks for example). I&amp;#x27;m going to leave that to you to discover. Once
you&amp;#x27;ve tried it out for a little bit, then
&lt;a href="https://youtu.be/_eVyLVFlSQk?list=PLV5CVI1eNcJgCrPH_e6d57KRUTiDZgs0u"&gt;watch me do it&lt;/a&gt;.
There&amp;#x27;s a catch with the way we&amp;#x27;ve been testing things a bit that change
slightly with hooks (thanks to JavaScript closures).&lt;/p&gt;&lt;h3&gt;The remaining use case for render props&lt;/h3&gt;&lt;p&gt;Ok, so we can refactor our components to use hooks, and even continue to export
react components with a render prop-based API (you might be interested, you may
even consider going all out with
&lt;a href="https://americanexpress.io/hydra"&gt;the hydra pattern&lt;/a&gt;). But let&amp;#x27;s imagine we&amp;#x27;re
now in a future where we don&amp;#x27;t need render props for logic reuse and everyone&amp;#x27;s
using hooks. Is there any reason to continue writing or using components that
expose a render props API?&lt;/p&gt;&lt;p&gt;YES! Observe! Here&amp;#x27;s
&lt;a href="https://github.com/downshift-js/downshift/blob/9b3467dce2be59832765277570857de5679d8392/stories/examples/windowing-with-react-virtualized.js"&gt;an example of using downshift with react-virtualized&lt;/a&gt;.
Here&amp;#x27;s the relevant bit:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;&amp;lt;List
// ... some props
rowRenderer={({key, index, style}) =&amp;gt; (
&amp;lt;div
// ... some props
/&amp;gt;
)}
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Checkout that &lt;code&gt;rowRenderer&lt;/code&gt; prop there. Do you know what that is? IT&amp;#x27;S A RENDER
PROP! What!? 🙀 That&amp;#x27;s inversion of control in all its glory with render props
right there. That&amp;#x27;s a prop that &lt;code&gt;react-virtualized&lt;/code&gt; uses to delegate control of
rendering rows in a list to you the user of the component. If
&lt;code&gt;react-virtualized&lt;/code&gt; were to be rewritten to use hooks, &lt;em&gt;maybe&lt;/em&gt; it could accept
the &lt;code&gt;rowRenderer&lt;/code&gt; as an argument to the &lt;code&gt;useVirtualized&lt;/code&gt; hook, but I don&amp;#x27;t
really see any benefit to that over it&amp;#x27;s current API. So I think render props
(and this style of inversion of control) are here to stay for use cases like
this.&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;I hope you find this interesting and helpful. Remember that React hooks are
still in alpha and subject to change. They are also completely opt-in and will
not require any breaking changes to React&amp;#x27;s API. I think that&amp;#x27;s a great thing.
Don&amp;#x27;t go rewriting your apps! Refactor them (once hooks are stable)!&lt;/p&gt;&lt;p&gt;Good luck!&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Learn more about Refactoring to React Hooks from me&lt;/strong&gt;:&lt;/p&gt;&lt;p&gt;&lt;a href="https://kentcdodds.com/blog/introducing-a-new-course-simplify-react-apps-with-react-hooks-and-suspense"&gt;My new egghead.io course&lt;/a&gt;
will show you how to refactor a typical app&amp;#x27;s components to use react hooks (and
React.lazy/suspense). It&amp;#x27;s a good time!&lt;/p&gt;&lt;p&gt;Also, check out
&lt;a href="http://kcd.im/hooks-and-suspense"&gt;this free egghead playlist about hooks and suspense&lt;/a&gt;!&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://github.com/dominictarr/event-stream/issues/116"&gt;npm malware event&lt;/a&gt;:
The package &lt;code&gt;event-stream&lt;/code&gt; was published with a dependency that tried to steal
bitcoin wallets. &lt;code&gt;event-stream&lt;/code&gt; is downloaded ~2million times per week, so
it&amp;#x27;s likely you&amp;#x27;ve been infected. Check
&lt;a href="https://blog.npmjs.org"&gt;the npm blog&lt;/a&gt;, I&amp;#x27;m sure they&amp;#x27;ll post more about it
soon.&lt;/li&gt;&lt;li&gt;&lt;a href="https://reactpodcast.simplecast.fm/29"&gt;React Podcast: 29: Don&amp;#x27;t Rewrite Your App for Hooks and Suspense with Jared Palmer&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/developit/htm"&gt;&lt;code&gt;htm&lt;/code&gt;&lt;/a&gt; by
&lt;a href="https://twitter.com/_developit/status/1065026506068504577"&gt;Jason Miller&lt;/a&gt;
looks pretty slick. I still prefer JSX, but I can appreciate what he&amp;#x27;s doing
there and the fact that there&amp;#x27;s no extra special syntax for things JavaScript
can do (like map an array) is a major plus :)&lt;/li&gt;&lt;li&gt;&lt;a href="https://medium.com/styled-components/announcing-native-support-for-the-css-prop-in-styled-components-245ca5252feb"&gt;Announcing native support for the css prop in styled-components 🎉&lt;/a&gt; — This
was always one of my biggest grievances with styled-components and a big
reason I preferred &lt;a href="https://emotion.sh"&gt;emotion&lt;/a&gt;. I still prefer emotion, but
I&amp;#x27;m really excited that styled-components has this feature now! Stop naming
things &amp;quot;Container&amp;quot; and &amp;quot;Wrapper!&amp;quot;&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/react-hooks-whats-going-to-happen-to-render-props"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Introducing a new course: Simplify React Apps with React Hooks and Suspense]]></title>
<description><![CDATA[Learn about the massive improvements coming to function components in React via
a fresh new course showing you how to refactor an existing app to these new and
upcoming APIs. Ok, before I get into things, can I just say that this course artwork by…]]></description>
<link>https://kentcdodds.com/blog/introducing-a-new-course-simplify-react-apps-with-react-hooks-and-suspense</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/introducing-a-new-course-simplify-react-apps-with-react-hooks-and-suspense</guid>
<pubDate>Mon, 03 Dec 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;&lt;em&gt;Learn about the massive improvements coming to function components in React via
a fresh new course showing you how to refactor an existing app to these new and
upcoming APIs.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;Ok, before I get into things, can I just say that this course artwork by&lt;/em&gt;
&lt;a href="https://twitter.com/mappletons"&gt;&lt;em&gt;Maggie Appleton&lt;/em&gt;&lt;/a&gt; &lt;em&gt;and&lt;/em&gt;
&lt;a href="https://twitter.com/MaximalGFX"&gt;&lt;em&gt;Maxime Bourgeois&lt;/em&gt;&lt;/a&gt; &lt;em&gt;is just the absolute best.
It&amp;#x27;s just so good. 😍&lt;/em&gt;&lt;/p&gt;&lt;p&gt;I&amp;#x27;m super excited to share this course with you. I&amp;#x27;ve been using React full time
for almost three years now and I&amp;#x27;ve never been more
&lt;a href="https://youtu.be/0jlTw2XI7I8?list=PLV5CVI1eNcJgCrPH_e6d57KRUTiDZgs0u"&gt;excited (!!)&lt;/a&gt;
about writing components than when I started playing around with Hooks and
Suspense. Let&amp;#x27;s get a quick rundown of what you can expect from the course:&lt;/p&gt;&lt;h3&gt;&lt;a href="https://egghead.io/courses/simplify-react-apps-with-react-hooks-and-suspense"&gt;About the course&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;With the massive improvements to function components in React via hooks and
suspense, you may be interested in seeing how to refactor a typical class
component to a simpler class component that uses React Suspense and Hooks
features. In this course, Kent will take
&lt;a href="https://github.com/kentcdodds/react-github-profile"&gt;a modern React codebase&lt;/a&gt;
that uses classes and refactor the entire thing to use function components as
much as possible. We&amp;#x27;ll look at state, side effects, async code, caching, and
more!&lt;/p&gt;&lt;p&gt;Want a primer on hooks and suspense?
&lt;a href="https://egghead.io/playlists/react-hooks-and-suspense-650307f2"&gt;Watch my React Hooks and Suspense Playlist&lt;/a&gt;!&lt;/p&gt;&lt;p&gt;&lt;em&gt;note: React Hooks is&lt;/em&gt; &lt;strong&gt;&lt;em&gt;alpha&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;and subject to change. The React team has&lt;/em&gt;
&lt;a href="https://reactjs.org/blog/2018/11/27/react-16-roadmap.html"&gt;&lt;em&gt;the 16.x roadmap here&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;&lt;h3&gt;&lt;a href="https://egghead.io/lessons/react-introduction-to-refactoring-a-react-application-to-react-hooks-and-react-suspense"&gt;Introduction to Refactoring a React Application to React Hooks and React Suspense&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Let&amp;#x27;s get a quick overview of what this course is all about and how it&amp;#x27;s been
structured to make sure you&amp;#x27;re as productive as possible with these new
features.&lt;/p&gt;&lt;h3&gt;&lt;a href="https://egghead.io/lessons/react-refactor-a-class-component-with-react-hooks-to-a-function"&gt;Refactor a Class Component with React hooks to a Function&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;We have a render prop based class component that allows us to make a GraphQL
request with a given query string and variables and uses a GitHub graphql client
that is in React context to make the request. Let&amp;#x27;s refactor this to a function
component that uses the hooks useReducer, useContext, and useEffect.&lt;/p&gt;&lt;h3&gt;&lt;a href="https://egghead.io/lessons/react-handle-deep-object-comparison-in-react-s-useeffect-hook-with-the-useref-hook"&gt;Handle Deep Object Comparison in React&amp;#x27;s useEffect hook with the useRef Hook&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;The second argument to React&amp;#x27;s &lt;code&gt;useEffect&lt;/code&gt; hook is an array of dependencies for
your &lt;code&gt;useEffect&lt;/code&gt; callback. When any value in that array changes, the effect
callback is re-run. But the &lt;code&gt;variables&lt;/code&gt; object we&amp;#x27;re passing to that array is
created during render, so our effect will be re-run every render even if the
shape of the object is the same. So let&amp;#x27;s solve this by doing our own equality
check from within the effect callback.&lt;/p&gt;&lt;h3&gt;&lt;a href="https://egghead.io/lessons/react-safely-setstate-on-a-mounted-react-component-through-the-useeffect-hook"&gt;Safely setState on a Mounted React Component through the useEffect Hook&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;In the class version of this component, we had a method called &lt;code&gt;safeSetState&lt;/code&gt;
which would check whether the component was still mounted before trying to call
&lt;code&gt;setState&lt;/code&gt;. This is because our graphql client library is unable to cancel
in-flight requests. Let&amp;#x27;s make that same kind of thing work by tracking the
mounted state of our component using the &lt;code&gt;useRef&lt;/code&gt; and &lt;code&gt;useEffect&lt;/code&gt; hooks.&lt;/p&gt;&lt;h3&gt;&lt;a href="https://egghead.io/lessons/react-extract-generic-react-hook-code-into-custom-react-hooks"&gt;Extract Generic React Hook Code into Custom React Hooks&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Because hooks code is regular JavaScript, extracting it to its own function is
trivial and enables code sharing in a really nice way. It also allows us to
encapsulate and separate concerns really cleanly. Custom hooks also compose
really nicely together to build more complex hooks out of more primitive ones.
Let&amp;#x27;s do this by creating a &lt;code&gt;useSetState&lt;/code&gt; and &lt;code&gt;useSafeSetState&lt;/code&gt;custom hook.&lt;/p&gt;&lt;p&gt;If you would like a more comprehensive &lt;code&gt;useSetState&lt;/code&gt; hook, give
&lt;a href="https://github.com/suchipi/use-legacy-state"&gt;&lt;code&gt;use-legacy-state&lt;/code&gt;&lt;/a&gt; a try.&lt;/p&gt;&lt;h3&gt;&lt;a href="https://egghead.io/lessons/react-track-values-over-the-course-of-renders-with-react-useref-in-a-custom-useprevious-hook"&gt;Track Values Over the Course of Renders with React useRef in a Custom usePrevious Hook&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Our hook to track the previous values looks pretty useful, so let&amp;#x27;s extract that
into it&amp;#x27;s own custom React Hook called &lt;code&gt;usePrevious&lt;/code&gt;.&lt;/p&gt;&lt;h3&gt;&lt;a href="https://egghead.io/lessons/react-deeply-compare-inputs-in-a-custom-react-hook-for-useeffect"&gt;Deeply Compare Inputs in a Custom React Hook for useEffect&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;It would be nice if &lt;code&gt;useEffect&lt;/code&gt; did the deep value comparison for us. Why don&amp;#x27;t
we make our own custom hook that does that for us? In this lesson we&amp;#x27;ll create a
&lt;code&gt;useDeepCompareEffect&lt;/code&gt; which will allow us to use it just like a &lt;code&gt;useEffect&lt;/code&gt;and
allow us to just pass the inputs.&lt;/p&gt;&lt;h3&gt;&lt;a href="https://egghead.io/lessons/react-refactor-a-react-class-component-with-usecontext-and-usestate-hooks"&gt;Refactor a React Class Component with useContext and useState Hooks&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;We&amp;#x27;ve got a pretty simple User class component that manages a bit of state and
uses some context. Let&amp;#x27;s refactor this over to a function component that uses
the &lt;code&gt;useContext&lt;/code&gt; and &lt;code&gt;useState&lt;/code&gt; hooks.&lt;/p&gt;&lt;h3&gt;&lt;a href="https://egghead.io/lessons/react-refactor-a-render-prop-component-to-a-custom-react-hook"&gt;Refactor a render Prop Component to a Custom React Hook&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Our &lt;code&gt;&amp;lt;Query /&amp;gt;&lt;/code&gt; component is a render prop based component that the &lt;code&gt;&amp;lt;User /&amp;gt;&lt;/code&gt;
component uses. But because it doesn&amp;#x27;t render anything, we can actually just
change it to a custom hook. Let&amp;#x27;s create a &lt;code&gt;useQuery&lt;/code&gt; hook that returns the
state from the hooks the Query component uses and use that instead. But we&amp;#x27;ll
preserve the component so we don&amp;#x27;t have to refactor everywhere that uses the
Query render prop based component as well and we can keep our tests passing as
they are.&lt;/p&gt;&lt;h3&gt;&lt;a href="https://egghead.io/lessons/react-handle-componentdidmount-and-componentwillunmount-in-react-component-refactor-to-hooks"&gt;Handle componentDidMount and componentWillUnmount in React Component Refactor to Hooks&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Let&amp;#x27;s refactor our &lt;code&gt;GitHubClientProvider&lt;/code&gt; class component to a function
component that uses hooks. This one&amp;#x27;s pretty interesting because we can use
&lt;code&gt;useEffect&lt;/code&gt; to encapsulate everything we need for a single effect, truly
separating that concern within our component.&lt;/p&gt;&lt;h3&gt;&lt;a href="https://egghead.io/lessons/react-dynamically-import-react-components-with-react-lazy-and-suspense"&gt;Dynamically Import React Components with React.lazy and Suspense&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;With React 16.6.0, React Suspense was officially released as a stable feature
(with limited support for &lt;code&gt;React.lazy&lt;/code&gt;). Let&amp;#x27;s refactor our lazily-loaded
components that are using
&lt;a href="https://github.com/jamiebuilds/react-loadable"&gt;&lt;code&gt;react-loadable&lt;/code&gt;&lt;/a&gt; to components
that use the built-in &lt;code&gt;React.lazy&lt;/code&gt;feature.&lt;/p&gt;&lt;h3&gt;&lt;a href="https://egghead.io/lessons/react-preload-react-components-with-the-useeffect-hook"&gt;Preload React Components with the useEffect Hook&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;While users are filling out the form on our home page, it would be a good idea
to pre-load the next page they will be going to so they don&amp;#x27;t have to wait for
it to load once they&amp;#x27;ve finished filling out the form. React&amp;#x27;s &lt;code&gt;useEffect&lt;/code&gt; hook
makes this really easy.&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/introducing-a-new-course-simplify-react-apps-with-react-hooks-and-suspense"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[How Gratitude can make you a better developer]]></title>
<description><![CDATA[This week in the United States we celebrate
Thanksgiving Day . In the US, the
celebration was started by Pilgrims who came to America in the 1620s on
the Mayflower . They had a pretty
rough time getting their settlement started and had help from…]]></description>
<link>https://kentcdodds.com/blog/how-gratitude-can-make-you-a-better-developer</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/how-gratitude-can-make-you-a-better-developer</guid>
<pubDate>Mon, 03 Dec 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;This week in the United States we celebrate
&lt;a href="https://en.wikipedia.org/wiki/Thanksgiving"&gt;Thanksgiving Day&lt;/a&gt;. In the US, the
celebration was started by Pilgrims who came to America in the 1620s on
&lt;a href="https://en.wikipedia.org/wiki/Mayflower"&gt;the Mayflower&lt;/a&gt;. They had a pretty
rough time getting their settlement started and had help from the Native
Americans. Together they celebrated and gave thanks to God for a good harvest
with a feast and that yearly tradition became the Thanksgiving holiday we
celebrate in the US today.&lt;/p&gt;&lt;p&gt;Each year, Thanksgiving gets more and more overshadowed with the commercialism
of Christmas. I want to take this opportunity to share with you some of the
things I&amp;#x27;m grateful for and also explain why I think that gratitude can help you
be a better software engineer and a better person.&lt;/p&gt;&lt;p&gt;When I was off
&lt;a href="https://twitter.com/kentcdodds/status/1043644565041819648"&gt;riding horses&lt;/a&gt; at a
family reunion last summer, my older brother gave a presentation about attitude
and gratitude.&lt;/p&gt;&lt;p&gt;He presented this graphic:&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:800px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/31f1388624e40846c9ba88e23e3f6e81/8ff1e/0.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:40%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="The Wheel of Experience: Positive" title="The Wheel of Experience: Positive" src="https://kentcdodds.com/static/31f1388624e40846c9ba88e23e3f6e81/8ff1e/0.png" srcSet="https://kentcdodds.com/static/31f1388624e40846c9ba88e23e3f6e81/f4a45/0.png 259w,https://kentcdodds.com/static/31f1388624e40846c9ba88e23e3f6e81/ef0f6/0.png 518w,https://kentcdodds.com/static/31f1388624e40846c9ba88e23e3f6e81/8ff1e/0.png 800w" sizes="(max-width: 800px) 100vw, 800px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;figcaption&gt;The Wheel of Experience: Positive&lt;/figcaption&gt;&lt;p&gt;Given any circumstance (which we often can&amp;#x27;t control), whether those
circumstances are positive or negative, we can control what we think of those
circumstances, and that impacts the outcome. Positive thoughts lead to positive
feelings, actions, and results.&lt;/p&gt;&lt;p&gt;Then he presented this alternative graphic:&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:800px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/a152bb241c9651d5ef66d2a66647ab57/8ff1e/1.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:55.99999999999999%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="The Wheel of Experience: Negative" title="The Wheel of Experience: Negative" src="https://kentcdodds.com/static/a152bb241c9651d5ef66d2a66647ab57/8ff1e/1.png" srcSet="https://kentcdodds.com/static/a152bb241c9651d5ef66d2a66647ab57/f4a45/1.png 259w,https://kentcdodds.com/static/a152bb241c9651d5ef66d2a66647ab57/ef0f6/1.png 518w,https://kentcdodds.com/static/a152bb241c9651d5ef66d2a66647ab57/8ff1e/1.png 800w" sizes="(max-width: 800px) 100vw, 800px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;figcaption&gt;The Wheel of Experience: Negative&lt;/figcaption&gt;&lt;p&gt;Here we have the same circumstances but respond with negative thoughts which
lead to negative feelings, followed by negative actions and then negative
results.&lt;/p&gt;&lt;p&gt;What&amp;#x27;s the big difference between these two experiences? Here we have them
together:&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:800px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/8711900eacb65744b556486964607bd9/8ff1e/2.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:48.75000000000001%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="The Wheel of Experience: Both — Attitude" title="The Wheel of Experience: Both — Attitude" src="https://kentcdodds.com/static/8711900eacb65744b556486964607bd9/8ff1e/2.png" srcSet="https://kentcdodds.com/static/8711900eacb65744b556486964607bd9/f4a45/2.png 259w,https://kentcdodds.com/static/8711900eacb65744b556486964607bd9/ef0f6/2.png 518w,https://kentcdodds.com/static/8711900eacb65744b556486964607bd9/8ff1e/2.png 800w" sizes="(max-width: 800px) 100vw, 800px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;figcaption&gt;The Wheel of Experience: Both — Attitude&lt;/figcaption&gt;&lt;p&gt;The turning point for both of these experiences is our thoughts. Our attitude
can help guide our thoughts automatically in a positive direction so we more
often wind up with positive feelings, actions, and results.&lt;/p&gt;&lt;p&gt;Let&amp;#x27;s try to make this more concrete. Imagine that your product manager comes to
you and says you have to stop experimenting with GraphQL because a new
requirement came in and it&amp;#x27;s critical to the business that everyone work on it.
That&amp;#x27;s a circumstance you can&amp;#x27;t control, but your attitude and what you think
about that circumstance can influence the result.&lt;/p&gt;&lt;p&gt;Let&amp;#x27;s take the negative route first. You think: &amp;quot;I&amp;#x27;ll bet that manager is just
making this up. They don&amp;#x27;t want us to take anymore time to learn GraphQL because
they never wanted to invest in it anyway.&amp;quot; 😠 This clearly will make you feel
resentful and upset at the product manager and the work they&amp;#x27;ve given you to do.
Because of these negative feelings, your behavior toward your manager and
co-workers is cold and bitter, and you make short-cuts on the work you&amp;#x27;ve been
given because you don&amp;#x27;t want to do it anyway and you think it&amp;#x27;s just something
your manager made up because they&amp;#x27;re petty. 😡 The result is a poorly thought
out solution that&amp;#x27;s not tested, ends up causing more problems, is code nobody
wants to touch, and it&amp;#x27;s a spiral down from there. 🌀&lt;/p&gt;&lt;p&gt;Now with the positive attitude, things change. You think: &amp;quot;Dang, I really wanted
to experiment with GraphQL and my branch will probably fall out of date, but
that&amp;#x27;s ok, I&amp;#x27;ll probably be able to get it back up to date when I&amp;#x27;m done with
this.&amp;quot; 😃 You get to work on the assignment you&amp;#x27;ve been given, hopeful that you
can finish it and get back to your GraphQL work, but also with the positive
attitude you approach all your work because you care about software craft and
want to make sure you don&amp;#x27;t have to deal with this when it&amp;#x27;s shipped. 🚢 The
result is a well crafted solution that&amp;#x27;s well tested and reviewed, you don&amp;#x27;t
have any problems when shipping to production so nobody needs to touch the code
anyway, you get back to your GraphQL work and turns out it&amp;#x27;s a smashing success
and you&amp;#x27;re promoted! 🥇 Good job! 👏&lt;/p&gt;&lt;p&gt;This is a contrived example, but hopefully you can see this as something that
could actually happen and you can see examples of times things have worked out
this way for you in the past (both negative and positive).&lt;/p&gt;&lt;p&gt;It&amp;#x27;s important to realize that &amp;quot;positive results&amp;quot; does not mean you&amp;#x27;ll
necessarily get the promotion like we have in this story, that&amp;#x27;s another thing
that&amp;#x27;s not entirely in your control. But one thing that is always in your
control are the attitude and thoughts you have given any circumstances.&lt;/p&gt;&lt;p&gt;After my brother explained this (though he didn&amp;#x27;t share that story, I made that
up on my own 😉), he showed us a clip from this video (I recommend you watch it
before continuing, but please... do come back 😅):&lt;/p&gt;&lt;figcaption&gt;The Gratitude Experiment&lt;/figcaption&gt;&lt;p&gt;So science 👩‍🔬🔬📊⚗️👨‍🔬 tells us that gratitude makes us happier! The video gives
a challenge, and this is the slide my brother showed us for his &amp;quot;Happiness
Invitation&amp;quot;&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:800px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/a4cea0e0bd841403434b30a48f448d49/8ff1e/3.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:71.00000000000001%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="Happiness Invitation" title="Happiness Invitation" src="https://kentcdodds.com/static/a4cea0e0bd841403434b30a48f448d49/8ff1e/3.png" srcSet="https://kentcdodds.com/static/a4cea0e0bd841403434b30a48f448d49/f4a45/3.png 259w,https://kentcdodds.com/static/a4cea0e0bd841403434b30a48f448d49/ef0f6/3.png 518w,https://kentcdodds.com/static/a4cea0e0bd841403434b30a48f448d49/8ff1e/3.png 800w" sizes="(max-width: 800px) 100vw, 800px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Step 1&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Journal for 1 week&lt;/li&gt;&lt;li&gt;5 minutes each night&lt;/li&gt;&lt;li&gt;&amp;quot;Things I am grateful for&amp;quot; (People, places, things...)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Step 2&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Look at your list and think &amp;quot;Who gave this to me?&amp;quot;&lt;/li&gt;&lt;li&gt;Express sincere gratitude to someone else (Letter; Private, personal
opportunity)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Step 3&lt;/p&gt;&lt;ul&gt;&lt;li&gt;After expressing gratitude, write down in detail how you feel now&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;One thing that I like about the video and this challenge is that it gives a path
for developing a better attitude. I think often our thoughts are automatic and
unless we&amp;#x27;re really trying, our brain with start thinking for us. This is where
&lt;strong&gt;mindfulness&lt;/strong&gt; kicks in. Being mindful of yourself and how you&amp;#x27;re feeling can
actually lead you to retraining your brain to think positively automatically. It
may be hard to change your thought process today, but given enough time and
effort, you can retrain your brain to do what will really bring you happiness.&lt;/p&gt;&lt;p&gt;I hope you join me this Thanksgiving in the happiness invitation. Tweet with the
hashtag
&lt;a href="https://twitter.com/hashtag/HappinessInvitation"&gt;&lt;strong&gt;#HappinessInvitation&lt;/strong&gt;&lt;/a&gt;
every time you do one of the steps (write in your journal, express gratitude,
and reflect) and let&amp;#x27;s hold each other accountable. Then next week we&amp;#x27;ll see how
we&amp;#x27;re all feeling and hopefully we can land that promotion we&amp;#x27;re looking for
😉🥇&lt;/p&gt;&lt;p&gt;Good luck!&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://github.com/szarouski/lerna-wizard"&gt;lerna-wizard&lt;/a&gt;: I&amp;#x27;ve been using
lerna and this helped me learn what I can do with the commands. Thanks
&lt;a href="https://twitter.com/webuniverseio"&gt;Sergey Zarouski&lt;/a&gt;!&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/alexanderson1993/react-konami-hook"&gt;useKonami&lt;/a&gt;: A custom
hook by &lt;a href="https://twitter.com/ralex1993"&gt;R. Alex Anderson&lt;/a&gt; for supporting
Konami code to your app 😍&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/pjDOJdMM2eg?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;Render Prop by Any Other Name&lt;/a&gt; — This
is a talk I gave at &lt;a href="https://twitter.com/FrameworkSummit"&gt;FrameworkSummit&lt;/a&gt; in
October with &lt;a href="https://twitter.com/ShortDiv"&gt;Divya Sasidharan&lt;/a&gt; (Vue) and
&lt;a href="https://twitter.com/MannIsaac"&gt;Isaac Mann&lt;/a&gt; (Angular) that compares similar
patterns across the frameworks. (There were other great talks there too, see
them on
&lt;a href="https://youtube.com/channel/UCUTZdTjqY9ypGfpYWvSHC2w"&gt;the Framework Summit YouTube channel&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/vhWaMPQhMLQ"&gt;React&amp;#x27;s New Defaults — Concurrent React and React Hooks&lt;/a&gt; — An
interesting talk about the future of React by
&lt;a href="https://twitter.com/swyx"&gt;Shawn Wang&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/zWsZcBiwgVE?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;GDG Salt Lake DevFest 2018: Why React Hooks&lt;/a&gt; — A
talk by me about why React Hooks are a thing and why I&amp;#x27;m super excited to get
them. &lt;a href="https://github.com/kentcdodds/gdg-devfest-2018-react"&gt;Demo repo&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/how-gratitude-can-make-you-a-better-developer"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[useEffect vs useLayoutEffect]]></title>
<description><![CDATA[Both of these can be used to do basically the same thing, but they have slightly
different use cases. So here are some rules for you to consider when deciding
which React Hook to use. useEffect 99% of the time this is what you want to use. When…]]></description>
<link>https://kentcdodds.com/blog/useeffect-vs-uselayouteffect</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/useeffect-vs-uselayouteffect</guid>
<pubDate>Mon, 26 Nov 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;Both of these can be used to do basically the same thing, but they have slightly
different use cases. So here are some rules for you to consider when deciding
which &lt;a href="https://reactjs.org/hooks"&gt;React Hook&lt;/a&gt; to use.&lt;/p&gt;&lt;h3&gt;&lt;a href="https://reactjs.org/docs/hooks-reference.html#useeffect"&gt;useEffect&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;99% of the time this is what you want to use. When hooks are stable and if you
refactor any of your class components to use hooks, you&amp;#x27;ll likely move any code
from &lt;code&gt;componentDidMount&lt;/code&gt;, &lt;code&gt;componentDidUpdate&lt;/code&gt;, and &lt;code&gt;componentWillUnmount&lt;/code&gt; to
&lt;code&gt;useEffect&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;The one catch&lt;/strong&gt; is that this runs &lt;em&gt;after&lt;/em&gt; react renders your component and
ensures that your effect callback does not block browser painting. This differs
from the behavior in class components where &lt;code&gt;componentDidMount&lt;/code&gt; and
&lt;code&gt;componentDidUpdate&lt;/code&gt; run synchronously after rendering. It&amp;#x27;s more performant
this way and most of the time this is what you want.&lt;/p&gt;&lt;p&gt;However, if your effect is mutating the DOM (via a DOM node ref) &lt;strong&gt;&lt;em&gt;and&lt;/em&gt;&lt;/strong&gt; the
DOM mutation will change the appearance of the DOM node between the time that it
is rendered and your effect mutates it, then you &lt;strong&gt;don&amp;#x27;t&lt;/strong&gt; want to use
&lt;code&gt;useEffect&lt;/code&gt;. You&amp;#x27;ll want to use &lt;code&gt;useLayoutEffect&lt;/code&gt;. Otherwise the user could see
a flicker when your DOM mutations take effect. &lt;strong&gt;This is pretty much the only
time you want to avoid &lt;code&gt;useEffect&lt;/code&gt; and use &lt;code&gt;useLayoutEffect&lt;/code&gt; instead.&lt;/strong&gt;&lt;/p&gt;&lt;h3&gt;&lt;a href="https://reactjs.org/docs/hooks-reference.html#uselayouteffect"&gt;useLayoutEffect&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;This runs synchronously immediately after React has performed all DOM mutations.
This can be useful if you need to make DOM measurements (like getting the scroll
position or other styles for an element) and then make DOM mutations &lt;strong&gt;or&lt;/strong&gt;
trigger a synchronous re-render by updating state.&lt;/p&gt;&lt;p&gt;As far as scheduling, this works the same way as &lt;code&gt;componentDidMount&lt;/code&gt; and
&lt;code&gt;componentDidUpdate&lt;/code&gt;. Your code runs immediately after the DOM has been updated,
but before the browser has had a chance to &amp;quot;paint&amp;quot; those changes (the user
doesn&amp;#x27;t actually see the updates until after the browser has repainted).&lt;/p&gt;&lt;h3&gt;Summary&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;useLayoutEffect:&lt;/strong&gt; If you need to mutate the DOM and/or DO need to perform
measurements&lt;/li&gt;&lt;li&gt;&lt;strong&gt;useEffect:&lt;/strong&gt; If you don&amp;#x27;t need to interact with the DOM at all or your DOM
changes are unobservable (seriously, most of the time you should use this).&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;&lt;a href="https://youtu.be/0jlTw2XI7I8?t=39s&amp;amp;list=PLV5CVI1eNcJgCrPH_e6d57KRUTiDZgs0u"&gt;I am extremely excited about React&amp;#x27;s upcoming hooks feature&lt;/a&gt;.
I think it&amp;#x27;s going to make React much easier to learn and use.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Learn more about React from me&lt;/strong&gt;:
&lt;a href="http://kcd.im/hooks-and-suspense"&gt;Hooks &amp;amp; Suspense Playlist on egghead.io&lt;/a&gt; — A
free 35 minute list of videos demoing how to use the new React Hooks and
Suspense features. (Note: these features are still pretty alpha and likely to
change).&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://usehooks.com"&gt;useHooks.com&lt;/a&gt; — One new React Hook recipe every day.
Really cool resource by &lt;a href="https://twitter.com/gabe_ragland"&gt;Gabe Ragland&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/sw-yx/fresh-concurrent-react"&gt;fresh-concurrent-react&lt;/a&gt; by
&lt;a href="https://twitter.com/swyx"&gt;Shawn Wang&lt;/a&gt; — an as up-to-date-as-possible resource
about the upcoming features in concurrent react! Really helpful if you want to
play around with Suspense and Concurrent React.&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/useeffect-vs-uselayouteffect"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Testing Implementation Details]]></title>
<description><![CDATA[Last year when I was using enzyme (like everyone else at the time), I stepped
carefully around certain APIs in enzyme. I
completely avoided shallow rendering ,
never used APIs like instance() , state() , or find('ComponentName') . And
in code…]]></description>
<link>https://kentcdodds.com/blog/testing-implementation-details</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/testing-implementation-details</guid>
<pubDate>Tue, 20 Nov 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;Last year when I was using enzyme (like everyone else at the time), I stepped
carefully around certain APIs in enzyme. I
&lt;a href="https://kentcdodds.com/blog/why-i-never-use-shallow-rendering"&gt;completely avoided shallow rendering&lt;/a&gt;,
&lt;em&gt;never&lt;/em&gt; used APIs like &lt;code&gt;instance()&lt;/code&gt;, &lt;code&gt;state()&lt;/code&gt;, or &lt;code&gt;find(&amp;#x27;ComponentName&amp;#x27;)&lt;/code&gt;. And
in code reviews of other people&amp;#x27;s pull requests I explained again and again why
it&amp;#x27;s important to avoid these APIs. The reason is they each allow your test to
test implementation details of your components. People often ask me what I mean
by &amp;quot;implementation details.&amp;quot; I mean, it&amp;#x27;s hard enough to test as it is! Why do
we have to make all these rules to make it harder?&lt;/p&gt;&lt;h3&gt;Why is testing implementation details bad?&lt;/h3&gt;&lt;p&gt;There are two distinct reasons that it&amp;#x27;s important to avoid testing
implementation details. Tests which test implementation details:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Can break when you refactor application code. &lt;strong&gt;False negatives&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;May not fail when you break application code. &lt;strong&gt;False positives&lt;/strong&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Let&amp;#x27;s take a look at each of these in turn, using the following simple accordion
component as an example:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;// accordion.js
import React from &amp;#x27;react&amp;#x27;
import AccordionContents from &amp;#x27;./accordion-contents&amp;#x27;
class Accordion extends React.Component {
state = {openIndex: 0}
setOpenIndex = openIndex =&amp;gt; this.setState({openIndex})
render() {
const {openIndex} = this.state
return (
&amp;lt;div&amp;gt;
{this.props.items.map((item, index) =&amp;gt; (
&amp;lt;&amp;gt;
&amp;lt;button onClick={() =&amp;gt; this.setOpenIndex(index)}&amp;gt;
{item.title}
&amp;lt;/button&amp;gt;
{index === openIndex ? (
&amp;lt;AccordionContents&amp;gt;{item.contents}&amp;lt;/AccordionContents&amp;gt;
) : null}
&amp;lt;/&amp;gt;
))}
&amp;lt;/div&amp;gt;
)
}
}
export default Accordion
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And here&amp;#x27;s a test that tests implementation details:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;// __tests__/accordion.enzyme.js
import React from &amp;#x27;react&amp;#x27;
// if you&amp;#x27;re wondering why not shallow,
// then please read https://kcd.im/shallow
import Enzyme, {mount} from &amp;#x27;enzyme&amp;#x27;
import EnzymeAdapter from &amp;#x27;enzyme-adapter-react-16&amp;#x27;
import Accordion from &amp;#x27;../accordion&amp;#x27;
// Setup enzyme&amp;#x27;s react adapter
Enzyme.configure({adapter: new EnzymeAdapter()})
test(&amp;#x27;setOpenIndex sets the open index state properly&amp;#x27;, () =&amp;gt; {
const wrapper = mount(&amp;lt;Accordion items={[]} /&amp;gt;)
expect(wrapper.state(&amp;#x27;openIndex&amp;#x27;)).toBe(0)
wrapper.instance().setOpenIndex(1)
expect(wrapper.state(&amp;#x27;openIndex&amp;#x27;)).toBe(1)
})
test(&amp;#x27;Accordion renders AccordionContents with the item contents&amp;#x27;, () =&amp;gt; {
const hats = {title: &amp;#x27;Favorite Hats&amp;#x27;, contents: &amp;#x27;Fedoras are classy&amp;#x27;}
const footware = {
title: &amp;#x27;Favorite Footware&amp;#x27;,
contents: &amp;#x27;Flipflops are the best&amp;#x27;,
}
const wrapper = mount(&amp;lt;Accordion items={[hats, footware]} /&amp;gt;)
expect(wrapper.find(&amp;#x27;AccordionContents&amp;#x27;).props().children).toBe(hats.contents)
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Raise your hand if you&amp;#x27;ve seen (or written) tests like this in your codebase
(🙌).&lt;/p&gt;&lt;p&gt;Ok, now let&amp;#x27;s take a look at how things break down with these tests...&lt;/p&gt;&lt;h3&gt;False negatives when refactoring&lt;/h3&gt;&lt;p&gt;A surprising number of people find testing distasteful, especially UI testing.
Why is this? There are various reasons for it, but one big reason I hear again
and again is that people spend way too much time babysitting the tests. &amp;quot;Every
time I make a change to the code, the tests break!&amp;quot; This is a real drag on
productivity! Let&amp;#x27;s see how our tests fall prey to this frustrating problem.&lt;/p&gt;&lt;p&gt;Let&amp;#x27;s say I come in and I&amp;#x27;m refactoring this accordion to prepare it to allow
for multiple accordion items to be open at once. A refactor doesn&amp;#x27;t change
existing behavior at all, it just changes the &lt;strong&gt;implementation&lt;/strong&gt;. So let&amp;#x27;s
change the &lt;strong&gt;implementation&lt;/strong&gt; in a way that doesn&amp;#x27;t change the behavior:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-diff"&gt;class Accordion extends React.Component {
- state = {openIndex: 0}
- setOpenIndex = openIndex =&amp;gt; this.setState({openIndex})
+ state = {openIndexes: [0]}
+ setOpenIndex = openIndex =&amp;gt; this.setState({openIndexes: [openIndex]})
render() {
- const {openIndex} = this.state
+ const {openIndexes} = this.state
return (
&amp;lt;div&amp;gt;
{this.props.items.map((item, index) =&amp;gt; (
&amp;lt;&amp;gt;
&amp;lt;button onClick={() =&amp;gt; this.setOpenIndex(index)}&amp;gt;
{item.title}
&amp;lt;/button&amp;gt;
- {index === openIndex ? (
+ {openIndexes.includes(index) ? (
&amp;lt;AccordionContents&amp;gt;{item.contents}&amp;lt;/AccordionContents&amp;gt;
) : null}
&amp;lt;/&amp;gt;
))}
&amp;lt;/div&amp;gt;
)
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Awesome, we do a quick check in the app and everything&amp;#x27;s still working properly,
so when we come to this component later to support opening multiple accordions,
it&amp;#x27;ll be a cinch! Then we run the tests and 💥kaboom💥 they&amp;#x27;re busted. Which one
broke? &lt;code&gt;setOpenIndex sets the open index state properly&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;What&amp;#x27;s the error message?&lt;/p&gt;&lt;pre&gt;&lt;code&gt;expect(received).toBe(expected)
Expected value to be (using ===):
0
Received:
undefined
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Is that test failure warning us of a real problem? Nope! The component still
works fine.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;This is what&amp;#x27;s called a false negative.&lt;/strong&gt; It means that we got a test failure,
but it was because of a broken test, not broken app code. I honestly cannot
think of a more annoying test failure situation. Oh well, let&amp;#x27;s go ahead and fix
our test:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-diff"&gt; test(&amp;#x27;setOpenIndex sets the open index state properly&amp;#x27;, () =&amp;gt; {
const wrapper = mount(&amp;lt;Accordion items={[]} /&amp;gt;)
- expect(wrapper.state(&amp;#x27;openIndex&amp;#x27;)).toEqual(0)
+ expect(wrapper.state(&amp;#x27;openIndexes&amp;#x27;)).toEqual([0])
wrapper.instance().setOpenIndex(1)
- expect(wrapper.state(&amp;#x27;openIndex&amp;#x27;)).toEqual(1)
+ expect(wrapper.state(&amp;#x27;openIndexes&amp;#x27;)).toEqual([1])
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The takeaway: Tests which test implementation details can give you a false
negative when you refactor your code. This leads to brittle and frustrating
tests that seem to break anytime you so much as look at the code.&lt;/p&gt;&lt;h3&gt;False positives&lt;/h3&gt;&lt;p&gt;Ok, so now let&amp;#x27;s say your co-worker is working in the Accordion and they see
this code:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;&amp;lt;button onClick={() =&amp;gt; this.setOpenIndex(index)}&amp;gt;{item.title}&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Immediately their premature performance optimization feelings kick in and they
say to themselves, &amp;quot;hey! inline arrow functions in &lt;code&gt;render&lt;/code&gt; are
&lt;a href="https://cdb.reacttraining.com/react-inline-functions-and-performance-bdff784f5578"&gt;bad for performance&lt;/a&gt;,
so I&amp;#x27;ll just clean that up! I think this should work, I&amp;#x27;ll just change it really
quick and run tests.&amp;quot;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;&amp;lt;button onClick={this.setOpenIndex}&amp;gt;{item.title}&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Cool. Run the tests and... ✅✅ awesome! They commit the code without checking
it in the browser because tests give confidence right? That commit goes in a
completely unrelated PR that changes thousands of lines of code and is
understandably missed. The accordion breaks in production and Nancy is unable to
get her tickets to see
&lt;a href="https://www.broadway-at-the-eccles.com/events/wicked"&gt;Wicked in Salt Lake next February&lt;/a&gt;.
Nancy is crying and your team feels horrible.&lt;/p&gt;&lt;p&gt;So what went wrong? Didn&amp;#x27;t we have a test to verify that the state changes when
&lt;code&gt;setOpenIndex&lt;/code&gt; is called &lt;em&gt;and&lt;/em&gt; that the accordion contents are displayed
appropriately!? Yes you did! But the problem is that there was no test to verify
that the button was wired up to &lt;code&gt;setOpenIndex&lt;/code&gt; correctly.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;This is called a false positive.&lt;/strong&gt; It means that we didn&amp;#x27;t get a test failure,
but we should have! So how do we cover ourselves to make sure this doesn&amp;#x27;t
happen again? We need to add another test to verify clicking the button updates
the state correctly. And then I need to add a coverage threshold of 100% code
coverage so we don&amp;#x27;t make this mistake again. Oh, and I should write a dozen or
so ESLint plugins to make sure people don&amp;#x27;t use these APIs that encourage
testing implementation details!&lt;/p&gt;&lt;p&gt;... But I&amp;#x27;m not going to bother... Ugh, I&amp;#x27;m just so tired of all these false
positives and negatives, I&amp;#x27;d almost rather not write tests at all. DELETE ALL
THE TESTS! Wouldn&amp;#x27;t it be nice if we had a tool that had a wider
&lt;a href="https://twitter.com/kentcdodds/status/859994199738900480"&gt;pit&lt;/a&gt; of
&lt;a href="https://blog.codinghorror.com/falling-into-the-pit-of-success"&gt;success&lt;/a&gt;? Yes it
would! And guess what, we DO have such a tool!&lt;/p&gt;&lt;h3&gt;Implementation detail free testing&lt;/h3&gt;&lt;p&gt;So we could rewrite all these tests with enzyme, limiting ourselves to APIs that
are free of implementation details, but instead, I&amp;#x27;m just going to use
&lt;a href="https://github.com/testing-library/react-testing-library"&gt;react-testing-library&lt;/a&gt;
which will make it very difficult to include implementation details in my tests.
Let&amp;#x27;s check that out now!&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;// __tests__/accordion.rtl.js
import React from &amp;#x27;react&amp;#x27;
import {render, fireEvent} from &amp;#x27;react-testing-library&amp;#x27;
import Accordion from &amp;#x27;../accordion&amp;#x27;
test(&amp;#x27;can open accordion items to see the contents&amp;#x27;, () =&amp;gt; {
const hats = {title: &amp;#x27;Favorite Hats&amp;#x27;, contents: &amp;#x27;Fedoras are classy&amp;#x27;}
const footware = {
title: &amp;#x27;Favorite Footware&amp;#x27;,
contents: &amp;#x27;Flipflops are the best&amp;#x27;,
}
const {getByText, queryByText} = render(
&amp;lt;Accordion items={[hats, footware]} /&amp;gt;,
)
expect(getByText(hats.contents)).toBeInTheDocument()
expect(queryByText(footware.contents)).toBeNull()
fireEvent.click(getByText(footware.title))
expect(getByText(footware.contents)).toBeInTheDocument()
expect(queryByText(hats.contents)).toBeNull()
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Sweet! A single test that verifies all the behavior really well. And this test
passes whether my state is called &lt;code&gt;openIndex&lt;/code&gt;, &lt;code&gt;openIndexes&lt;/code&gt;, or &lt;code&gt;tacosAreTasty&lt;/code&gt;
🌮. Nice! Got rid of that false negative! And if I wire up my click handler
incorrectly, this test will fail. Sweet, got rid of that false positive too! And
I didn&amp;#x27;t have to memorize any list of rules or install a bunch of annoying
ESLint plugins. I just use the tool in the typical usage, and I get a test that
actually can give me confidence my accordion is working as the user wants it
too.&lt;/p&gt;&lt;h3&gt;So... What are implementation details then?&lt;/h3&gt;&lt;p&gt;Here&amp;#x27;s the simplest definition I can come up with:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Implementation details are things which users of your code will not typically
use, see, or even know about.&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;So the first question we need an answer to is: &amp;quot;Who is the user of this code.&amp;quot;
Well, the end user who will be interacting with our component in the browser is
definitely a user. They&amp;#x27;ll be observing and interacting with the rendered
buttons and contents. But we also have the developer who will be rendering the
accordion with props (in our case, a given list of items). So React components
typically have two users: end-users, and developers. &lt;strong&gt;End-users and developers
are the two &amp;quot;users&amp;quot; that our application code needs to consider.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Great, so what parts of our code do each of these users use, see, and know
about? The end user will see/interact with what we render in the &lt;code&gt;render&lt;/code&gt;
method. The developer will see/interact with the props they pass to the
component. So our test should typically only see/interact with the props that
are passed, and the rendered output.&lt;/p&gt;&lt;p&gt;This is precisely what the
&lt;a href="https://github.com/testing-library/react-testing-library"&gt;react-testing-library&lt;/a&gt;
test does. It passes fake props to the Accordion, then it interacts with the
rendered output by querying the output for the contents that will be displayed
to the user (or ensuring that it wont be displayed) and clicking the buttons
that are rendered.&lt;/p&gt;&lt;p&gt;Now consider the enzyme test. With enzyme, we access the &lt;code&gt;state&lt;/code&gt; of &lt;code&gt;openIndex&lt;/code&gt;.
This is not something that either of our users care about directly. They don&amp;#x27;t
know that&amp;#x27;s what it&amp;#x27;s called, they don&amp;#x27;t know whether the open index is stored
as a single primitive value, or stored as an array, and frankly they don&amp;#x27;t care.
They also don&amp;#x27;t know or care about the &lt;code&gt;setOpenIndex&lt;/code&gt; method specifically. And
yet, our test knows about both of these implementation details.&lt;/p&gt;&lt;p&gt;This is what makes our enzyme test prone to false negatives. Because &lt;strong&gt;by making
our test use the component differently than end-users and developers do, we
create a third user our application code needs to consider: the tests!&lt;/strong&gt; And
frankly, the tests are one user that nobody cares about. I don&amp;#x27;t want my
application code to consider the tests. What a complete waste of time. I don&amp;#x27;t
want tests that are written for their own sake. &lt;em&gt;Automated tests should verify
that the application code works for the production users.&lt;/em&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;&lt;a href="https://twitter.com/kentcdodds/status/977018512689455106"&gt;The more your tests resemble the way your software is used, the more confidence they can give you.&lt;/a&gt;
 — me&lt;/em&gt;&lt;/p&gt;&lt;p&gt;Read more about this in &lt;a href="https://kentcdodds.com/blog/avoid-the-test-user"&gt;Avoid the Test User&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Oh, and &lt;a href="https://reactjs.org/hooks"&gt;React Hooks&lt;/a&gt; got you all excited? If you
rewrite that accordion component to use React hooks, the enzyme test fails
terribly, while the
&lt;a href="https://github.com/testing-library/react-testing-library"&gt;react-testing-library&lt;/a&gt;
test continues to work.&lt;/p&gt;&lt;p&gt;&lt;img src="https://kentcdodds.com/0-11dc2676f0b2705b5aabf1fe925b8c51.gif" alt="happy goats"/&gt;&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;So how do you avoid testing implementation details? Using the right tools is a
good start. A few weeks ago I sent this process for how to know what to test,
following this process helps you have the right mindset when testing and you
will naturally avoid implementation details:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;What part of your untested codebase would be really bad if it broke? (The
checkout process)&lt;/li&gt;&lt;li&gt;Try to narrow it down to a unit or a few units of code (When clicking the
&amp;quot;checkout&amp;quot; button a request with the cart items is sent to /checkout)&lt;/li&gt;&lt;li&gt;Look at that code and consider who the &amp;quot;users&amp;quot; are (The developer rendering
the checkout form, the end user clicking on the button)&lt;/li&gt;&lt;li&gt;Write down a list of instructions for that user to manually test that code
to make sure it&amp;#x27;s not broken. (render the form with some fake data in the
cart, click the checkout button, ensure the mocked /checkout API was called
with the right data, respond with a fake successful response, make sure the
success message is displayed).&lt;/li&gt;&lt;li&gt;Turn that list of instructions into an automated test.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;I hope that&amp;#x27;s helpful to you! If you really want to take your testing to the
next level, then I definitely recommend you get a Pro license for
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;🏆&lt;/p&gt;&lt;p&gt;Good luck!&lt;/p&gt;&lt;p&gt;P.S. If you&amp;#x27;d like to play around with all this,
&lt;a href="https://codesandbox.io/s/rlnw1r5nxo"&gt;here&amp;#x27;s a codesandbox&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;P.S.P.S. As an exercise for you... What happens to that second enzyme test if I
change the name of the &lt;code&gt;AccordionContents&lt;/code&gt; component? {insert biggest eye roll
ever}&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/testing-implementation-details"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Common Testing Mistakes]]></title>
<description><![CDATA[Mistake Number 0 One of the biggest mistakes you could make would be missing out on my full
Testing JS course . (see what I did there?) Mistake Number 1: Testing Implementation Details I harp on this a lot ( read more ). It's
because it's a huge…]]></description>
<link>https://kentcdodds.com/blog/common-testing-mistakes</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/common-testing-mistakes</guid>
<pubDate>Mon, 12 Nov 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;h3&gt;Mistake Number 0&lt;/h3&gt;&lt;p&gt;One of the biggest mistakes you could make would be missing out on my full
&lt;a href="https://testingjavascript.com"&gt;Testing JS course&lt;/a&gt;. (see what I did there?)&lt;/p&gt;&lt;h3&gt;Mistake Number 1: Testing Implementation Details&lt;/h3&gt;&lt;p&gt;I harp on this a lot (&lt;a href="https://kentcdodds.com/blog/testing-implementation-details"&gt;read more&lt;/a&gt;). It&amp;#x27;s
because it&amp;#x27;s a huge problem in testing and leads to tests that don&amp;#x27;t give nearly
as much confidence as they could. Here&amp;#x27;s a very simple example of a test that&amp;#x27;s
testing implementation details:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;// counter.js
import React from &amp;#x27;react&amp;#x27;
export class Counter extends React.Component {
state = {count: 0}
increment = () =&amp;gt; this.setState(({count}) =&amp;gt; ({count: count + 1}))
render() {
const {count} = this.state
return &amp;lt;button onClick={this.increment}&amp;gt;{count}&amp;lt;/button&amp;gt;
}
}
// __tests__/counter.js
import React from &amp;#x27;react&amp;#x27;
// (it&amp;#x27;s hard to test implementation details with react-testing-library,
// so we&amp;#x27;ll use enzyme in this example 😅)
import {mount} from &amp;#x27;enzyme&amp;#x27;
import {Counter} from &amp;#x27;../counter&amp;#x27;
test(&amp;#x27;the increment method increments count&amp;#x27;, () =&amp;gt; {
const wrapper = mount(&amp;lt;Counter /&amp;gt;)
// don&amp;#x27;t ever do this:
expect(wrapper.instance().state.count).toBe(0)
wrapper.instance().increment()
expect(wrapper.instance().state.count).toBe(1)
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So why is this testing implementation details? Why is it so bad to test
implementation details? Here are two truths about tests that focus on
implementation details like the test above:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;I can break the code and not the test (eg: I could make a typo in my
button&amp;#x27;s onClick assignment)&lt;/li&gt;&lt;li&gt;I can refactor the code and break the test (eg: I could rename increment to
updateCount)&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;These kinds of tests are the worst to maintain because you&amp;#x27;re constantly
updating them (due to point #2), and they don&amp;#x27;t even give you solid confidence
(due to point #1).&lt;/p&gt;&lt;p&gt;In &lt;a href="https://testingjavascript.com"&gt;my course&lt;/a&gt; I&amp;#x27;ll show you the right way to
write tests and avoid this common mistake.&lt;/p&gt;&lt;h3&gt;Mistake Number 2: 100% code coverage&lt;/h3&gt;&lt;p&gt;Trying to go for 100% code coverage for an application is a total mistake and I
see this all the time. Interestingly I&amp;#x27;ve normally seen this as a mandate from
management, but wherever it&amp;#x27;s coming from it&amp;#x27;s coming out of a misunderstanding
of what a code coverage report can and cannot tell you about the confidence you
can have in your codebase.&lt;/p&gt;&lt;p&gt;What code coverage is telling you:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;This code was run when your tests were run.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;What code coverage is NOT telling you:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;This code will work according to the business requirements.&lt;/li&gt;&lt;li&gt;This code works with all the other code in the application.&lt;/li&gt;&lt;li&gt;The application cannot get into a bad state&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Another problem with code coverage reports is that every line of covered code
adds just as much to the overall coverage report as any other line. What this
means is that you can increase your code coverage just as much by adding tests
to your &amp;quot;About us&amp;quot; page as you can by adding tests to your &amp;quot;Checkout&amp;quot; page. One
of those things is more important than the other, and code coverage can&amp;#x27;t give
you any insight into that for your codebase...&lt;/p&gt;&lt;p&gt;There&amp;#x27;s no one-size-fits-all solution for a good code coverage number to shoot
for. Every application&amp;#x27;s needs are different. I concern myself less with the
code coverage number and more with how confident I am that the important parts
of my application are covered. I use the code coverage report to help me &lt;em&gt;after&lt;/em&gt;
I&amp;#x27;ve already identified which parts of my application code are critical. It
helps me to know if I&amp;#x27;m missing some edge cases the code is covering but my
tests are not.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;I should note that for open source modules, going for 100% code coverage is
totally appropriate because they&amp;#x27;re generally a lot easier to keep at 100%
(because they&amp;#x27;re smaller and more isolated) and they&amp;#x27;re really important code
due to the fact that they&amp;#x27;re shared in multiple projects.&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I talked a bit about this in
&lt;a href="https://youtu.be/O2tsvUJT09U?index=9&amp;amp;list=PLV5CVI1eNcJgCrPH_e6d57KRUTiDZgs0u&amp;amp;t=0s"&gt;my livestream&lt;/a&gt;
the other day, check it out!&lt;/p&gt;&lt;h3&gt;Mistake Number 3: Repeat Testing&lt;/h3&gt;&lt;p&gt;One of the biggest complaints people have about end-to-end (E2E) tests is how
slow and brittle they are when compared to integration or unit tests. There&amp;#x27;s no
way you&amp;#x27;ll ever get a single E2E test as fast or reliable as a single unit test.
It&amp;#x27;s just never going to happen. That said a single E2E test will get you WAY
more confidence than a single unit test. In fact, there are some corners of
confidence that are impossible to get out of unit tests that E2E tests are great
at, so it&amp;#x27;s definitely worth having them around!&lt;/p&gt;&lt;p&gt;But this doesn&amp;#x27;t mean that we can&amp;#x27;t make our E2E tests faster and more reliable
than you&amp;#x27;ve likely experienced in the past. Repeat testing is a common mistake
that people make when writing E2E tests that contribute to the poor performance
and reliability.&lt;/p&gt;&lt;p&gt;&lt;a href="https://kentcdodds.com/blog/test-isolation-with-react"&gt;Tests should always work in isolation&lt;/a&gt;. So
that means every test should be executed as a different user. So every test will
need to register and login as a brand new user right? Right. So you need to have
a few page objects for the registration and login pages because you&amp;#x27;ll be
running through those pages in every test right? WRONG! That&amp;#x27;s the mistake!&lt;/p&gt;&lt;p&gt;Let&amp;#x27;s take a step back. Why are you writing tests? So you can ship your
application with confidence that things wont break! Let&amp;#x27;s say you have 100 tests
that need an authenticated user. How many times do you need to run through the
&amp;quot;happy path&amp;quot; registration flow to be confident that flow works? 100 times or 1
time? I think it&amp;#x27;s safe to say that if it worked once, it should work every
time. So those 99 extra runs don&amp;#x27;t give you any extra confidence. &lt;strong&gt;That&amp;#x27;s
wasted effort.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;So what do you do instead? I mean, we already established that your tests should
work in isolation so you shouldn&amp;#x27;t be sharing a user between them. Here&amp;#x27;s what
you do: make the same HTTP calls in your tests that your application makes when
you register and log in a new user! Those requests will be MUCH faster than
clicking and typing around the page and there&amp;#x27;s less of a chance for false
negative failures. And as long as you keep one test around that actually &lt;em&gt;does&lt;/em&gt;
test the registration/login flow you haven&amp;#x27;t lost any confidence that this flow
works.&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;Always remember the reason that you&amp;#x27;re testing is about confidence. If something
your test is doing isn&amp;#x27;t bringing you more confidence, then consider whether you
can stop doing it!&lt;/p&gt;&lt;p&gt;Good luck!&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/common-testing-mistakes"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[UI Testing Myths]]></title>
<description><![CDATA[Myth 1: "Tests always break when I make any changes to the code" This is actually a truth... if the tests are written incorrectly. If your test
is testing implementation details, then of course they'll break when the
implementation changes! But your…]]></description>
<link>https://kentcdodds.com/blog/ui-testing-myths</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/ui-testing-myths</guid>
<pubDate>Thu, 08 Nov 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;h3&gt;Myth 1: &amp;quot;Tests always break when I make any changes to the code&amp;quot;&lt;/h3&gt;&lt;p&gt;This is actually a truth... if the tests are written incorrectly. If your test
is testing implementation details, then of course they&amp;#x27;ll break when the
implementation changes! But your user doesn&amp;#x27;t care about the implementation
details. In fact, they don&amp;#x27;t even care whether you&amp;#x27;re using React, Angular, or
jQuery. So for the most part, your tests shouldn&amp;#x27;t care about that either. 💯&lt;/p&gt;&lt;p&gt;Unfortunately, many tools out there encourage testing implementation details. Do
that and you&amp;#x27;ll often wind up rewriting tests. &amp;quot;Why am I even testing this!?&amp;quot;
you&amp;#x27;ll ask yourself, and I don&amp;#x27;t blame you. That&amp;#x27;s why on
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt; I show you how test the
&lt;em&gt;right&lt;/em&gt; way.&lt;/p&gt;&lt;h3&gt;Myth 2: &amp;quot;I can&amp;#x27;t test a &amp;#x27;connected&amp;#x27; redux component&amp;quot;&lt;/h3&gt;&lt;p&gt;The conventional wisdom of testing components that use Redux is that you should
test the component in isolation from Redux, and then test the Redux action
creators and reducers separately.&lt;/p&gt;&lt;p&gt;But if you do this, your tests can&amp;#x27;t give you any confidence that your
components communicate properly &lt;em&gt;with&lt;/em&gt; Redux.&lt;/p&gt;&lt;p&gt;Instead, you can actually test your connected component with your real Redux
store. Do this, and you&amp;#x27;ll get the confidence that your component is rendering
properly, &lt;em&gt;and&lt;/em&gt; that the Redux action creators and reducers are all working
together in tandem. Just like they will in production. ✅&lt;/p&gt;&lt;p&gt;On &lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;, I show you how to
test in this way. The same concepts apply for React Router 🔀 and other
providers (like the Theme Provider from &lt;a href="https://emotion.sh"&gt;emotion&lt;/a&gt; 👩‍🎤), and
the course will show how to apply this method to those, too!&lt;/p&gt;&lt;h3&gt;Myth 3: &amp;quot;End-to-End tests are slow and brittle&amp;quot;&lt;/h3&gt;&lt;p&gt;This, too, can be true if the tests are written incorrectly. A common mistake I
see in E2E testing is doing the same things in every test — for instance, every
test going through the whole registration and login flow before doing whatever
is needed for the test. When you do stuff like this, you start seeing a lot of
duplication, and that&amp;#x27;s when you start creating things like &amp;quot;page objects&amp;quot;
(which is a poor practice). 😐&lt;/p&gt;&lt;p&gt;On &lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;, I show you how you
can get confidence that the registration and login flows are working, and then
skip those for the rest of your tests so you can significantly speed up the
tests and reduce the points of failure. When you write tests this way and use
tools like
&lt;a href="https://github.com/testing-library/cypress-testing-library"&gt;cypress-testing-library&lt;/a&gt;,
practices like page objects are totally unnecessary, and your tests are easier
to maintain, more reliable, and run faster. You might even find yourself
replacing Chrome with Cypress as your development workflow tool (which I show
you how to do in the course as well!) 😱&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/ui-testing-myths"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[The Merits of Mocking]]></title>
<description><![CDATA[The more your tests resemble the way your software is used, the more
confidence they can give
you. —  me One of the biggest challenges people face with testing is knowing what to test .
There are lots of reasons for that, but one big, flashing-lights…]]></description>
<link>https://kentcdodds.com/blog/the-merits-of-mocking</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/the-merits-of-mocking</guid>
<pubDate>Mon, 05 Nov 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;The more your tests resemble the way your software is used, the more
confidence they can give
you. — &lt;/em&gt;&lt;a href="https://twitter.com/kentcdodds/status/977018512689455106"&gt;&lt;em&gt;me&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;a href="https://twitter.com/kentcdodds/status/1048645068616163328"&gt;One of the biggest challenges people face with testing is knowing what to test&lt;/a&gt;.
There are lots of reasons for that, but one big, flashing-lights reason is
mocking. Many people don&amp;#x27;t know when to add a mock version of code or have their
test run the actual code directly. These are challenges I&amp;#x27;ll help you work
through in the JavaScript Mocking Fundamentals module of my Testing JavaScript
course.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Mocking lets you fake it so you &lt;em&gt;can&lt;/em&gt; make it.&lt;/strong&gt; If you couldn&amp;#x27;t have a fake
version of certain modules or services, testing the checkout process of an app
would cost you a lot of money in credit card fees. Talk about paying a high
price for confidence! 🤑 So instead, we make a fake version of that credit card
charging service to avoid paying the fees.&lt;/p&gt;&lt;p&gt;But mocking comes with a cost of its own.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Mocking severs the real-world connection between what you&amp;#x27;re testing and what
you&amp;#x27;re mocking.&lt;/strong&gt; Even if we have confidence that our code works with our fake
version of the credit card service, we can&amp;#x27;t have 100% confidence that our code
will work in production with the real version of the credit card service.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;When you mock something, you&amp;#x27;re making a trade-off.&lt;/strong&gt; You&amp;#x27;re trading
confidence for something else. For me, that something else is usually
practicality — meaning I wouldn&amp;#x27;t be able to test this thing at all, or it may
be pretty difficult/messy, without mocking. (Like in our credit card example.)&lt;/p&gt;&lt;p&gt;&lt;strong&gt;In my UI unit and integration tests, I have a rule.&lt;/strong&gt; I never make actual
network calls; instead, I&amp;#x27;ll mock the server response by mocking the module
responsible for making the network calls. I&amp;#x27;ll also mock animation libraries to
avoid waiting for animations before elements are removed from the page. Other
than that, most of my UI tests are using the real production code. For E2E
tests, I avoid mocking anything (with the exception of the backend hitting fake
or test services and not actual credit card services, for example).&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Saving a few milliseconds per test?&lt;/strong&gt; That&amp;#x27;s not a good reason to mock. People
like shallow rendering — component mocking to the max — because it&amp;#x27;s faster.
That&amp;#x27;s true, but we&amp;#x27;re talking milliseconds faster. If it takes a long time to
render your entire component tree, sounds to me like you have a real performance
bug in your software that needs to be addressed. I realize that time adds up
(50ms per test * 1000 tests = 50 seconds). But the less you mock, the fewer
tests you need, and trading confidence for a minute or two faster test suite is
a bad trade. 😵&lt;/p&gt;&lt;p&gt;&lt;strong&gt;There&amp;#x27;s a time and a place for mocking.&lt;/strong&gt; And when you need to mock, Jest
makes it easy with some really sweet mocking utilities. In
&lt;a href="https://testingjavascript.com"&gt;testingjavascript.com&lt;/a&gt; I&amp;#x27;ll show you how to
implement some of Jest&amp;#x27;s mocking capabilities in raw node so you can get an idea
of what&amp;#x27;s going on. It&amp;#x27;s brilliant. Here&amp;#x27;s an example of simulating Jest&amp;#x27;s
inline mock functionality in pure node:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;function fn(impl = () =&amp;gt; {}) {
const mockFn = (...args) =&amp;gt; {
mockFn.mock.calls.push(args)
return impl(...args)
}
mockFn.mock = {calls: []}
return mockFn
}
const utilsPath = require.resolve(&amp;#x27;../utils&amp;#x27;)
require.cache[utilsPath] = {
id: utilsPath,
filename: utilsPath,
loaded: true,
exports: {
getWinner: fn((p1, p2) =&amp;gt; p1),
},
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now, any code that requires that utils module will get the mock function version
of that module.&lt;/p&gt;&lt;p&gt;It&amp;#x27;s not quite as capable as Jest&amp;#x27;s inline mocking abilities, but we&amp;#x27;ll cover
that in more hands-on detail in the JavaScript Mocking Fundamentals module of
the course!&lt;/p&gt;&lt;p&gt;See you &lt;a href="https://testingjavascript.com"&gt;there&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;— Kent.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://6figuredev.com/podcast/episode-061-react-with-kent-c-dodds"&gt;Episode 061 — React with Kent C. Dodds&lt;/a&gt;
on &lt;a href="https://6figuredev.com"&gt;The 6 Figure Developer podcast&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/the-merits-of-mocking"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[The time I messed up]]></title>
<description><![CDATA[We all have stories where automated tests could've saved us from disaster, but I
want to tell you a story of a time when I went overboard with a certain testing
practice and it went really badly for me... This was a few years ago. I was working on…]]></description>
<link>https://kentcdodds.com/blog/the-time-i-messed-up</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/the-time-i-messed-up</guid>
<pubDate>Mon, 22 Oct 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;We all have stories where automated tests could&amp;#x27;ve saved us from disaster, but I
want to tell you a story of a time when I went overboard with a certain testing
practice and it went really badly for me...&lt;/p&gt;&lt;p&gt;This was a few years ago. I was working on
&lt;a href="https://github.com/formly-js/angular-formly"&gt;angular-formly&lt;/a&gt; and I had just
discovered React&amp;#x27;s PropTypes feature. I thought it was the coolest thing since
sliced bread. lol, I just looked it up and
&lt;a href="https://github.com/facebook/react/issues/2206"&gt;my first issue&lt;/a&gt; on the React
repo was asking if we could add an objectWith PropType validator. I wrote the
whole thing including tests and put that in the issue. Sophie Alpert responded
with:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Isn&amp;#x27;t this what React.PropTypes.shape is for?&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Ha! Whoops! Anyway, I decided it&amp;#x27;d be really cool to have development-only
runtime validation on the configuration object that people pass to
angular-formly when configuring their forms.&lt;/p&gt;&lt;p&gt;&lt;a href="https://github.com/facebook/react/issues/3079"&gt;My second issue&lt;/a&gt; on the React
repo was asking if the React team would be willing to extract prop types into
its own package (this has actually now taken place! Checkout
&lt;a href="http://npm.im/prop-types"&gt;prop-types&lt;/a&gt;). That didn&amp;#x27;t work out, so I decided to
write my own package and thus
&lt;a href="https://github.com/kentcdodds/api-check"&gt;api-check&lt;/a&gt; was born!&lt;/p&gt;&lt;p&gt;One of the cool things about a library like this is that the whole thing is a
bunch of pure functions! And we all know that pure functions are super easy to
test, right?! Also, because I had a very clear picture of what I wanted to
implement (with prop-types as my inspiration) I thought test-driven development
would be a synch.&lt;/p&gt;&lt;p&gt;So I set to work. I started writing a bunch of tests and implemented api-check
as I went. Honestly, it was exhilarating. (I&amp;#x27;d say intoxicating, but I&amp;#x27;ve never
actually had a drop of alcohol in my life, so I wouldn&amp;#x27;t know 😅). I was having
a blast writing this out.&lt;/p&gt;&lt;p&gt;But as time went on, I started noticing something... It was becoming
progressively less fun and more difficult to implement the behaviors as I added
them. The library code started getting really complicated. Now I shudder even
thinking about it. There&amp;#x27;s no way you could convince me to work on that code
anymore.&lt;/p&gt;&lt;p&gt;So what went wrong? I thought TDD was the process by which you create
beautifully and intentionally designed software. But what I was left with is a
mess that I don&amp;#x27;t want to touch. I must have done something wrong...&lt;/p&gt;&lt;p&gt;I did. TDD is a three-step process. It&amp;#x27;s often referred to as the &amp;quot;red, green,
refactor cycle&amp;quot;&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:676px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/12bcb6f09fd6ef9bbb497dafd6e73143/5fd36/0.jpg" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:97.92899408284025%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="TDD Cycle" title="TDD Cycle" src="https://kentcdodds.com/static/12bcb6f09fd6ef9bbb497dafd6e73143/5fd36/0.jpg" srcSet="https://kentcdodds.com/static/12bcb6f09fd6ef9bbb497dafd6e73143/d2274/0.jpg 259w,https://kentcdodds.com/static/12bcb6f09fd6ef9bbb497dafd6e73143/34151/0.jpg 518w,https://kentcdodds.com/static/12bcb6f09fd6ef9bbb497dafd6e73143/5fd36/0.jpg 676w" sizes="(max-width: 676px) 100vw, 676px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Here&amp;#x27;s the way it works:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;🚨 &lt;strong&gt;Red&lt;/strong&gt;: Write a test for the function/module you&amp;#x27;re going to create before
it exists/supports the feature you&amp;#x27;re adding. This gives you a test that fails
(you get a &amp;quot;red&amp;quot; error message).&lt;/li&gt;&lt;li&gt;✅ &lt;strong&gt;Green&lt;/strong&gt;: Implement just enough code to get that test passing (you get a
&amp;quot;green&amp;quot; success message).&lt;/li&gt;&lt;li&gt;🌀 &lt;strong&gt;Refactor&lt;/strong&gt;: Look over the code you have written and refactor it to ensure
it&amp;#x27;s well-written, as easy as possible to read/understand, and well-designed.
(The cool thing with this step is that you now have a test in place that will
tell you if you break something as you refactor).&lt;/li&gt;&lt;li&gt;🔁 &lt;strong&gt;Repeat&lt;/strong&gt;: It&amp;#x27;s a cycle, after all 😉 Keep going until you&amp;#x27;ve finished
implementing everything you need to.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;So where did I go wrong with api-check? Well, I kinda skipped the refactor step.
I got so excited from the &amp;quot;high&amp;quot; (another thing of which I&amp;#x27;m ignorant) that I
felt from turning that red test to a green test that I just continued on with
the next feature without stopping to consider if what I was building was at all
maintainable. Turns out it wasn&amp;#x27;t. I was building a monstrosity of
difficult-to-understand code. The code was legacy the second it left my fingers.&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;So, what do we learn from this? Test-driven development is awesome, and it can
really help you develop great code in certain situations. But if you skip the
refactor step and aren&amp;#x27;t intentional about what you&amp;#x27;re building, it can lead to
disaster.&lt;/p&gt;&lt;p&gt;Be careful out there, friends. And learn to use TDD the right way with me at
&lt;a href="https://testingjavascript.com/?utm_source=kcd-list&amp;amp;utm_medium=email&amp;amp;utm_campaign=early-bird"&gt;TestingJavaScript.com&lt;/a&gt;
🏆&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/the-time-i-messed-up"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[React is an implementation detail]]></title>
<description><![CDATA[I'm so excited about the response to my new
Testing JavaScript course! I knew the developer
community needed help with testing the right way, but... wow. I'm floored. 🙏 But if you haven't signed up yet (or even if you have), let's talk about…]]></description>
<link>https://kentcdodds.com/blog/react-is-an-implementation-detail</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/react-is-an-implementation-detail</guid>
<pubDate>Sat, 20 Oct 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;I&amp;#x27;m &lt;strong&gt;so excited&lt;/strong&gt; about the response to my new
&lt;a href="http://testingjavascript.com"&gt;Testing JavaScript&lt;/a&gt; course! I knew the developer
community needed help with testing the right way, but... wow. I&amp;#x27;m floored. 🙏&lt;/p&gt;&lt;p&gt;But if you &lt;em&gt;haven&amp;#x27;t&lt;/em&gt; signed up yet (or even if you have), let&amp;#x27;s talk about React
for a minute.&lt;/p&gt;&lt;p&gt;If you&amp;#x27;ve been following me for a while, you know I&amp;#x27;m pretty excited about
React. I&amp;#x27;m most effective with React, and I don&amp;#x27;t use any other frameworks to
get work done on the frontend.&lt;/p&gt;&lt;p&gt;But I&amp;#x27;m also a big fan of avoiding testing implementation details, and &lt;strong&gt;React
is an implementation detail!!&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Guess what that means? All the stuff we talk about in
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt; is relatively easy to
apply with other frameworks — like whichever framework you&amp;#x27;re using right now,
or will use in the future.&lt;/p&gt;&lt;p&gt;In fact, I have an entire course showing you how to get up and running with your
own testing utility and enjoy the same benefits that you&amp;#x27;ll see with
react-testing-library. That&amp;#x27;s thanks to the fact that react-testing-library
itself is a very small library, and the real brains behind it is
dom-testing-library — which is totally framework-agnostic! Cool right!? 😎&lt;/p&gt;&lt;p&gt;In fact,
&lt;a href="https://github.com/kentcdodds/dom-testing-library-with-anything/blob/9361a120bc52334968e94a10363bab9724d5dbd3/jquery.test.js"&gt;check out this example&lt;/a&gt;
from the course for testing a jQuery plugin with dom-testing-library:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;import &amp;#x27;jest-dom/extend-expect&amp;#x27;
import $ from &amp;#x27;jquery&amp;#x27;
import {getQueriesForElement, fireEvent} from &amp;#x27;dom-testing-library&amp;#x27;
$.fn.countify = function countify() {
this.html(`
&amp;lt;div&amp;gt;
&amp;lt;button&amp;gt;0&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;
`)
const $button = this.find(&amp;#x27;button&amp;#x27;)
$button._count = 0
$button.click(() =&amp;gt; {
$button._count++
$button.text($button._count)
})
}
// tests:
test(&amp;#x27;counter increments&amp;#x27;, () =&amp;gt; {
const div = document.createElement(&amp;#x27;div&amp;#x27;)
$(div).countify()
const {getByText} = getQueriesForElement(div)
const counter = getByText(&amp;#x27;0&amp;#x27;)
fireEvent.click(counter)
expect(counter).toHaveTextContent(&amp;#x27;1&amp;#x27;)
fireEvent.click(counter)
expect(counter).toHaveTextContent(&amp;#x27;2&amp;#x27;)
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The other frameworks are even better, considering most modern frameworks are
component-based. What&amp;#x27;s so cool is that 99% of the tests you write with these
tools will look basically the same regardless of what framework you use! That&amp;#x27;s
a huge win.&lt;/p&gt;&lt;p&gt;The hardest part is figuring out how to get some DOM from your component into
the document. And one of the course modules shows you how to do that with 11
frameworks and libraries! I think you&amp;#x27;ll really like this part of the course!&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/react-is-an-implementation-detail"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Eliminate an entire category of bugs with a few simple tools]]></title>
<description><![CDATA[You've probably heard of ESLint, Prettier, and Flow/TypeScript. These are static
code analysis tools that are wildly popular in the JavaScript ecosystem. I
consider them all testing tools. Let's take a look at each: ESLint ESLint is the pluggable…]]></description>
<link>https://kentcdodds.com/blog/eliminate-an-entire-category-of-bugs-with-a-few-simple-tools</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/eliminate-an-entire-category-of-bugs-with-a-few-simple-tools</guid>
<pubDate>Thu, 18 Oct 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;You&amp;#x27;ve probably heard of ESLint, Prettier, and Flow/TypeScript. These are static
code analysis tools that are wildly popular in the JavaScript ecosystem. I
consider them all testing tools. Let&amp;#x27;s take a look at each:&lt;/p&gt;&lt;h3&gt;&lt;a href="https://eslint.org"&gt;ESLint&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;ESLint is the pluggable linting utility for JavaScript. Linting is the process
of analyzing code for potential errors without actually running the code.
Consider this code:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;if (!&amp;#x27;serviceWorker&amp;#x27; in navigator) {
// the user&amp;#x27;s using an old browser :-(
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Do you spot the problem? If you do, that&amp;#x27;s great! But don&amp;#x27;t you think it&amp;#x27;d be
cool to not have to use your brain power to find and correct subtle bugs like
this one? I do! Make a computer do as much of my work for me as possible, please
and thank you. That&amp;#x27;s what ESLint does for you.&lt;/p&gt;&lt;h3&gt;&lt;a href="https://prettier.io"&gt;Prettier&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Prettier is the JavaScript code formatter. It&amp;#x27;ll take your code however you
write it, and reformat it in a way that&amp;#x27;s consistent and legible every time.
People often give me quizzical looks when I refer to Prettier as a testing tool.
But check this out:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;const a = false
const b = false
const c = true
const d = a &amp;amp;&amp;amp; b || c
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;What&amp;#x27;s the value of &lt;code&gt;d&lt;/code&gt; here? Do you know the order of operations of those
operators by heart? If you do, great! But do you trust that all the engineers on
your team know them well enough to not introduce a bug when refactoring this?&lt;/p&gt;&lt;p&gt;Run that code through Prettier, and this is what you get:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;const a = false
const b = false
const c = true
const d = (a &amp;amp;&amp;amp; b) || c
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Even if you do know the order of operations, the extra parentheses — which
Prettier automatically adds when you save the file — are quite helpful. And if
you realize that&amp;#x27;s not what you wanted, then you can add the parentheses
yourself and Prettier will leave it that way (&lt;code&gt;const d = a &amp;amp;&amp;amp; (b || c)&lt;/code&gt;).&lt;/p&gt;&lt;p&gt;This is one example of things Prettier does to make the intent of your code more
obvious — freeing your brain to focus on harder problems.&lt;/p&gt;&lt;h3&gt;&lt;a href="https://flow.org"&gt;Flow&lt;/a&gt;/&lt;a href="https://www.typescriptlang.org"&gt;TypeScript&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;These are static type checkers for JavaScript. A static type checker adds syntax
to JavaScript to allow you to specify what data type a variable is. It can
follow that variable through the code to make sure it&amp;#x27;s being used properly. (No
more &lt;code&gt;x is not a function&lt;/code&gt;.)&lt;/p&gt;&lt;p&gt;Can you spot the bug in this code?&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;function getFullName(user) {
const {
name: {first, middle, last},
} = user
return [first, middle, last].filter(Boolean).join(&amp;#x27;&amp;#x27;)
}
getFullName({first: &amp;#x27;Joe&amp;#x27;, middle: &amp;#x27;Bud&amp;#x27;, last: &amp;#x27;Matthews&amp;#x27;})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Maybe you can, maybe you can&amp;#x27;t. Maybe your coworkers can, maybe they can&amp;#x27;t. In
any case, wouldn&amp;#x27;t it be cool if we had some software that could spot the issue
for us? If we run that code with Flow, here&amp;#x27;s what we get:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ flow-example.js:8:13
Cannot call getFullName with object literal bound to user because
property name is missing in object literal [1].
5│ return [first, middle, last].filter(Boolean).join(&amp;#x27;&amp;#x27;)
6│ }
7│
[1] 8│ getFullName({first: &amp;#x27;Joe&amp;#x27;, middle: &amp;#x27;Bud&amp;#x27;, last: &amp;#x27;Matthews&amp;#x27;})
9│
10│
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So without changing our code at all, we get notified something&amp;#x27;s wrong. Nice!
Now, what if we add type annotations?&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;// @flow
type User = {
name: {
first: string,
middle: string,
last: string,
},
}
function getFullName(user: User): string {
const {
name: {first, middle, last},
} = user
return [first, middle, last].filter(Boolean).join(&amp;#x27;&amp;#x27;)
}
getFullName({first: &amp;#x27;Joe&amp;#x27;, middle: &amp;#x27;Bud&amp;#x27;, last: &amp;#x27;Matthews&amp;#x27;})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now if we run Flow on this, the error is even more helpful:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ flow-example.js:15:13
Cannot call getFullName with object literal bound to user because
property name is missing in object literal [1] but exists in
User [2].
[2] 10│ function getFullName(user: User): string {
11│ const {name: {first, middle, last}} = user
12│ return [first, middle, last].filter(Boolean).join(&amp;#x27;&amp;#x27;)
13│ }
14│
[1] 15│ getFullName({first: &amp;#x27;Joe&amp;#x27;, middle: &amp;#x27;Bud&amp;#x27;, last: &amp;#x27;Matthews&amp;#x27;})
16│
17|
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I like to consider type definitions with Flow or TypeScript to be a form of
inline automated tests. I strongly recommend you give it a shot if you haven&amp;#x27;t
yet. Incremental adoption is possible with these tools (especially if you&amp;#x27;re
already using babel, you can just start using &lt;code&gt;babel-preset-{flow,typescript}&lt;/code&gt;).
Try it out on your next feature and see what you think.&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;Static code analysis is a great way to get a significant boost of
confidence — fast, easily, and with less effort than writing unit tests for the
entire codebase. That&amp;#x27;s why it forms the base of
&lt;a href="https://twitter.com/kentcdodds/status/960723172591992832"&gt;the Testing Trophy 🏆&lt;/a&gt;.
If you&amp;#x27;re not using these tools already, start now.&lt;/p&gt;&lt;p&gt;Oh, and that big thing I&amp;#x27;m working on that I&amp;#x27;ve been teasing you about? I&amp;#x27;ve got
a bunch of stuff in there showing how to set up these tools. Look forward to it
😉&lt;/p&gt;&lt;p&gt;Subscribe &lt;a href="http://kcd.im/news"&gt;here&lt;/a&gt;:&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://youtu.be/7LmrS2sdMlo?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;React... Suspense... (@ SLC frontend meetup)&lt;/a&gt; — Livestream
of my talk at
&lt;a href="https://www.meetup.com/SLC-FE-DEV/events/254256621"&gt;https://www.meetup.com/SLC-FE-DEV/eve...&lt;/a&gt;.
In this talk I build my own simple-cache-provider to teach you how React
Suspense works with the cache and resources (promise throwers).&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/facebook/create-react-app/issues/5103"&gt;Last call for Create React App v2&lt;/a&gt; +
&lt;a href="https://youtu.be/1ERAJG9ILhk?list=PLV5CVI1eNcJgCrPH_e6d57KRUTiDZgs0u"&gt;Using and writing custom babel macros with create-react-app v2&lt;/a&gt;
(which is a &lt;a href="http://kcd.im/devtips"&gt;DevTipsWithKent livestream&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/kN7-EBjSilU?list=PLV5CVI1eNcJgCrPH_e6d57KRUTiDZgs0u"&gt;Validation with HTMLInputElements&lt;/a&gt; — A
&lt;a href="http://kcd.im/devtips"&gt;DevTipsWithKent&lt;/a&gt; livestream where I show you a sweet
validation feature that&amp;#x27;s built-into browsers since IE10!&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/eliminate-an-entire-category-of-bugs-with-a-few-simple-tools"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Why you've been bad about testing]]></title>
<description><![CDATA[The argument is long ended: You should be testing your mission-critical
code. Everyone accepts that testing code now is better than waiting for users to
complain later . Everyone agrees that the testing should be automated. Pretty much everyone's…]]></description>
<link>https://kentcdodds.com/blog/why-youve-been-bad-about-testing</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/why-youve-been-bad-about-testing</guid>
<pubDate>Mon, 15 Oct 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;The argument is long ended: &lt;strong&gt;You should be testing your mission-critical
code.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Everyone accepts that testing &lt;em&gt;code&lt;/em&gt; now is better than waiting for users to
complain &lt;em&gt;later&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Everyone agrees that the testing should be automated.&lt;/p&gt;&lt;p&gt;Pretty much everyone&amp;#x27;s had a situation where tests saved them from a production
bug...or would have saved them if tests had been in place.&lt;/p&gt;&lt;p&gt;But there&amp;#x27;s still a struggle.
&lt;a href="https://twitter.com/kentcdodds/status/1048645068616163328"&gt;The other day I asked on twitter&lt;/a&gt;
what you all struggle with around testing. The struggle comes when you&amp;#x27;re trying
to determine what to test, how much time you have to test, what granularity to
test, what to mock and what to keep real, or just the daunting task of setting
up good testing tools and testing environments. Or the frustration might creep
in when you find yourself writing the same code in two places. 🤪&lt;/p&gt;&lt;p&gt;Another big source of frustration with testing — stop us if you&amp;#x27;ve heard this
one before — is when you have to basically rewrite your tests every time you
touch the code it&amp;#x27;s testing. Once you pick your head up off your keyboard, you
have to ask yourself: &amp;quot;Ok... so why are we testing again? This is just adding
friction to shipping code.&amp;quot; It&amp;#x27;s extremely frustrating when you refactor a
component and your test breaks. 😡 I wouldn&amp;#x27;t want to write tests either.&lt;/p&gt;&lt;p&gt;When I got started with testing years ago, I struggled. I struggled hard. I&amp;#x27;ve
spent countless hours learning, building, and rebuilding tools. I even gave a
&lt;em&gt;full hour&lt;/em&gt; talk called
&lt;a href="https://kentcdodds.com/talks/#es6-webpack-karma-and-code-coverage"&gt;&amp;quot;ES6, Webpack, Karma, and Code Coverage&amp;quot;&lt;/a&gt;.
It took a full 60 minutes to explain how to make these tools play nicely
together. It took dozens more hours behind the scenes to figure out what I
explain in that talk.&lt;/p&gt;&lt;p&gt;But I was committed to figuring out and helping build the best way to do this. I
needed it, and I know my fellow developers need it too.&lt;/p&gt;&lt;p&gt;Struggle and frustration don&amp;#x27;t have to be your experience. You don&amp;#x27;t have to
spend dozens of hours to figure out how to get testing set up in your codebase.
&lt;strong&gt;I&amp;#x27;ve already done that for you.&lt;/strong&gt; And the tools have improved, and I can show
you how to use them. There are techniques I can teach you that will alleviate
the pain and struggle you&amp;#x27;re having with getting the confidence you&amp;#x27;re looking
for out of your testbase.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Here&amp;#x27;s a tip&lt;/strong&gt; for you to take the next time you test your code that&amp;#x27;ll help
you answer the question of &amp;quot;what do I test?&amp;quot; Follow this process:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;What part of your untested codebase would be really bad if it broke? (The
checkout process)&lt;/li&gt;&lt;li&gt;Try to narrow it down to a unit or a few units of code (When clicking the
&amp;quot;checkout&amp;quot; button a request with the cart items is sent to /checkout)&lt;/li&gt;&lt;li&gt;Look at that code and consider who the &amp;quot;users&amp;quot; are (The developer rendering
the checkout form, the end user clicking on the button)&lt;/li&gt;&lt;li&gt;Write down a list of instructions for that user to manually test that code
to make sure it&amp;#x27;s not broken. (render the form with some fake data in the
cart, click the checkout button, ensure the mocked /checkout API was called
with the right data, respond with a fake successful response, make sure the
success message is displayed).&lt;/li&gt;&lt;li&gt;Turn that list of instructions into an automated test.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;With the tools and techniques I&amp;#x27;m going to show you, this process will become a
natural habit. 💯&lt;/p&gt;&lt;p&gt;Stop the struggle. Follow me.&lt;/p&gt;&lt;p&gt;P.S. Stay tuned, because over the next couple weeks I&amp;#x27;ll share more strategy and
tactics for getting your testing skills up to date.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt; — This is the huge
thing that I wont stop talking about 😉&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/palmerhq/react-suspense-starter"&gt;&lt;code&gt;react-suspense-starter&lt;/code&gt;&lt;/a&gt;:
If you haven&amp;#x27;t had a chance to checkout suspense yet and play around with it,
check this out :)&lt;/li&gt;&lt;li&gt;&lt;a href="http://kcd.im/devtips"&gt;DevTipsWithKent&lt;/a&gt; — If you haven&amp;#x27;t watched any of these
yet, I recommend you give them a look. I&amp;#x27;m going to be doing some scheduled
livestreams soon that you&amp;#x27;ll want to catch live for sure!&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/why-youve-been-bad-about-testing"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Demystifying Testing]]></title>
<description><![CDATA[In the next few weeks, you're going to get bonus emails from me as I prepare to
launch the biggest undertaking I've ever taken. You'll love it. (Trust me, I've
run the tests. 😉) Many of you have messaged me, confused about where to get started with…]]></description>
<link>https://kentcdodds.com/blog/demystifying-testing</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/demystifying-testing</guid>
<pubDate>Thu, 11 Oct 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;In the next few weeks, you&amp;#x27;re going to get bonus emails from me as I prepare to
launch the biggest undertaking I&amp;#x27;ve ever taken. You&amp;#x27;ll love it. (Trust me, I&amp;#x27;ve
run the tests. 😉)&lt;/p&gt;&lt;p&gt;Many of you have messaged me, confused about where to get started with testing.
Just like everything else in software, we work hard to build abstractions to
make our jobs easier. But that amount of abstraction evolves over time, until
the only ones who &lt;em&gt;really&lt;/em&gt; understand it are the ones who built the abstraction
in the first place. Everyone else is left with taking the terms, APIs, and tools
at face value and struggling to make things work.&lt;/p&gt;&lt;p&gt;If there&amp;#x27;s one thing I believe about abstraction in code, it&amp;#x27;s that the
abstraction is &lt;em&gt;not&lt;/em&gt; magic, it&amp;#x27;s code. If there&amp;#x27;s another I thing I believe
about abstraction in code, it&amp;#x27;s that it&amp;#x27;s easier to learn by doing.&lt;/p&gt;&lt;p&gt;Here&amp;#x27;s an example:&lt;/p&gt;&lt;p&gt;Imagine that a less seasoned engineer approaches you. They&amp;#x27;re hungry to learn,
they want to be confident in their code, and they&amp;#x27;re ready to start testing. 👍
Ever prepared to learn from you, they&amp;#x27;ve written down a list of terms, APIs, and
concepts they&amp;#x27;d like you to define for them:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Assertion&lt;/li&gt;&lt;li&gt;Testing Framework&lt;/li&gt;&lt;li&gt;The &lt;code&gt;describe&lt;/code&gt;/&lt;code&gt;it&lt;/code&gt;/&lt;code&gt;beforeEach&lt;/code&gt;/&lt;code&gt;afterEach&lt;/code&gt;/&lt;code&gt;test&lt;/code&gt; functions&lt;/li&gt;&lt;li&gt;Mocks/Stubs/Test Doubles/Spies&lt;/li&gt;&lt;li&gt;Unit/Integration/End to end/Functional/Accessibility/Acceptance/Manual testing&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;So.........&lt;/p&gt;&lt;p&gt;Could you rattle off definitions for that budding engineer? Can you explain the
difference between an assertion library and a testing framework? Or are they
easier for you to &lt;em&gt;identify&lt;/em&gt; than &lt;em&gt;explain&lt;/em&gt;?&lt;/p&gt;&lt;p&gt;Here&amp;#x27;s the point. The better you understand these terms and abstractions, the
more effective you will be at teaching them. And if you can teach them, &lt;strong&gt;you&amp;#x27;ll
be more effective at &lt;em&gt;using&lt;/em&gt; them, too.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Enter a teach-an-engineer-to-fish moment. Did you know that you can &lt;em&gt;write your
own&lt;/em&gt; assertion library and testing framework? We often think of these
abstractions as beyond our capabilities, but they&amp;#x27;re not. Each of the popular
assertion libraries and frameworks started with a single line of code, followed
by another and then another. &lt;strong&gt;You don&amp;#x27;t need any tools to write a simple
test.&lt;/strong&gt; Here&amp;#x27;s an example:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;const {sum} = require(&amp;#x27;../math&amp;#x27;)
const result = sum(3, 7)
const expected = 10
if (result !== expected) {
throw new Error(`${result} is not equal to ${expected}`)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Put that in a module called &lt;code&gt;test.js&lt;/code&gt; and run it with &lt;code&gt;node test.js&lt;/code&gt; and poof,
you can start getting confidence that the &lt;code&gt;sum&lt;/code&gt;function from the &lt;code&gt;math.js&lt;/code&gt;
module is working as expected. Make that run on CI and you can get the
confidence that it won&amp;#x27;t break as changes are made to the codebase. 🏆&lt;/p&gt;&lt;p&gt;Once you understand how the abstractions work at a fundamental level, you&amp;#x27;ll
probably want to use them because hey, you just learned to fish and now you can
go fishing. And we have some pretty phenomenal fish, uh, tools available to us.
My favorite is the &lt;a href="https://jestjs.io"&gt;Jest&lt;/a&gt; testing platform. It&amp;#x27;s amazingly
capable and fully featured and allows me to write tests that give me the
confidence I need to not break things as I change code.&lt;/p&gt;&lt;p&gt;I&amp;#x27;m really looking forward to what I&amp;#x27;m creating for you. I think it&amp;#x27;ll help
accelerate your understanding of testing tools and abstractions by giving you
the chance to implement parts from scratch. The (hopeful) result? You can start
writing tests that are maintainable and built to instill confidence in your code
day after day.&lt;/p&gt;&lt;p&gt;Stay tuned. 🎣&lt;/p&gt;&lt;p&gt;P.S. Give this a try:
&lt;a href="https://twitter.com/intent/tweet?status=%23AssertionLibVsTestingFramework"&gt;Tweet&lt;/a&gt;
what&amp;#x27;s the difference between a testing framework and an assertion library? In
my course, I&amp;#x27;ll not only explain it, we&amp;#x27;ll build our own!&lt;/p&gt;&lt;p&gt;P.P.S. Set your alarms and
&lt;a href="https://twitter.com/intent/tweet?status=%E2%9A%A0%EF%B8%8F%20Hey%20friends!%20%40kentcdodds%20is%20working%20on%20a%20HUGE%20series%20of%20courses%20%28%3E100%20videos%20total!%29%20and%20you%20don%27t%20want%20to%20miss%20it.%20Subscribe%20to%20his%20newsletter%20to%20get%20a%20special%20discount%20when%20it%27s%20launched%3A%20kcd.im/news%20%F0%9F%92%8C"&gt;tell your friends&lt;/a&gt;!
On &lt;strong&gt;Friday Oct 19th&lt;/strong&gt; my course goes on sale with early-bird pricing! It is
HUGE. Like over 100 dense videos huge. Like ~5 dense hours of testing huge.
Seriously, &lt;strong&gt;let people know.&lt;/strong&gt; They don&amp;#x27;t want to miss this.&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/demystifying-testing"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Confidently Shipping Code]]></title>
<description><![CDATA[Have you read the book "Start With Why" ? If
you haven't, I recommend it. At least watch
the TED talk . The premise of the idea is that
"People won't truly buy into a product, service, movement, or idea until they
understand the WHY behind it…]]></description>
<link>https://kentcdodds.com/blog/confidently-shipping-code</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/confidently-shipping-code</guid>
<pubDate>Mon, 08 Oct 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;Have you read the book &lt;a href="https://startwithwhy.com/books"&gt;&amp;quot;Start With Why&amp;quot;&lt;/a&gt;? If
you haven&amp;#x27;t, I recommend it. At least watch
&lt;a href="https://youtu.be/u4ZoJKF_VuA"&gt;the TED talk&lt;/a&gt;. The premise of the idea is that
&amp;quot;People won&amp;#x27;t truly buy into a product, service, movement, or idea until they
understand the WHY behind it.&amp;quot; This concept hit home with me when I watched that
talk and then read the book a few years ago, and it&amp;#x27;s shaped the way I
communicate with you in my blog posts, talks, workshops, and courses.&lt;/p&gt;&lt;p&gt;I&amp;#x27;d like to share my &amp;quot;why&amp;quot; about testing with you and invite you to consider
what your own &amp;quot;why&amp;quot; might be.&lt;/p&gt;&lt;p&gt;Like many people, at the start of my career I didn&amp;#x27;t understand automated
software testing. I was introduced to it by my friend
&lt;a href="https://twitter.com/josepheames"&gt;Joe Eames&lt;/a&gt;, who was then fighting an uphill
battle at the company where we both worked to get people to write tests. I was
an intern at the time, and he took me under his wing a few times to teach me
about automated testing. I thought it was pretty neat, but he moved on to
another job before I really got testing ingrained in my workflow.&lt;/p&gt;&lt;p&gt;Later, when I started writing my first JavaScript library
(&lt;a href="https://github.com/kentcdodds/genie"&gt;geniejs&lt;/a&gt;), I realized quickly that
spending time to manually verify that everything&amp;#x27;s working, every single time I
fixed a bug or added a new feature, was pretty annoying. I decided to learn to
test and write tests for my library.
(&lt;a href="https://github.com/kentcdodds/genie/blob/166572f9fa82e6ec0893f90c7d6a99a49632dace/src/__tests__/index.js"&gt;The tests&lt;/a&gt;
have been through a few testing framework refactorings, but they&amp;#x27;re still
largely the same as when I originally wrote them all those years ago). Investing
time into testing my library ended up saving me a TON of time, and I was able to
integrate testing into my workflow.&lt;/p&gt;&lt;p&gt;I remember when I was actively working on angular-formly, I had a coworker who
needed a new feature. It was a simple feature, so he sat by me and watched as I
wrote the test, implemented the feature, and pushed the commit to trigger a
release. He was shocked that I could rely on the tests so much that I was
confident I didn&amp;#x27;t break anything. That was when it really occurred to me that
testing had become more than a default workflow for saving time. It was a
mechanism for giving me confidence.&lt;/p&gt;&lt;p&gt;At the time of this writing,
&lt;a href="https://www.npmjs.com/~kentcdodds"&gt;I have 111 packages published on npm&lt;/a&gt;.
Pretty much every one of those packages has 100% code coverage, meaning every
line is run in the tests. I don&amp;#x27;t think I could possibly maintain them any other
way. &lt;strong&gt;My libraries have received contributions from thousands of people.&lt;/strong&gt; When
someone opens a pull request with changes to one of my libraries, I have a
continuous integration service (&lt;a href="https://travis-ci.org"&gt;TravisCI&lt;/a&gt;) that kicks
off to run all the tests. Sometimes it&amp;#x27;s been months or even years since I&amp;#x27;ve
touched the code. Past Kent, who had just barely written the code, probably knew
instantly whether something broke. Present Kent? He usually has no idea, and it
would take me a lot of time to evaluate. Having the tests in place is like Past
Kent telling Present Kent: &amp;quot;It&amp;#x27;s ok. This is very unlikely to break anything.&amp;quot;
The tests save me time, and they give me — and all the users of my libraries — a
great amount of peace of mind.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;So why do I write tests?&lt;/strong&gt; I write tests because they allow me to accomplish
more than I could otherwise. I now have thousands of Kents in the form of
automated tests telling me whether changes are breaking use cases. With that
venerable army of robots, I&amp;#x27;m able to rest easy and get more accomplished.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Now, I want to ask you a question:&lt;/strong&gt; Why do you want to learn testing? Is it
to further your career? Did a specific incident (i.e. a bug — yup, we&amp;#x27;ve all
been there) happen that prompted a need? Do you (like me) simply want to get
more done, with more peace of mind?&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Now my next question:&lt;/strong&gt; What has been holding you back from starting?&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;Whether you&amp;#x27;re already testing, or you&amp;#x27;re interested in getting started, I&amp;#x27;ve
got something coming that I think you&amp;#x27;ll love. Especially if you&amp;#x27;ve struggled to
know what to test. I&amp;#x27;ve been working hard putting together &lt;strong&gt;the most
comprehensive work of my life&lt;/strong&gt;, and I think it&amp;#x27;ll knock your socks off. Stay
tuned.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com &lt;/a&gt;— I&amp;#x27;m about to release
a HUGE series of courses that you&amp;#x27;ll definitely want to checkout. Early bird
pricing starts on October 19th.&lt;/li&gt;&lt;li&gt;&lt;a href="https://reach.tech/workshops?a=kent"&gt;Professional React Training from Ryan Florence&lt;/a&gt; — I
strongly recommend you look. &lt;a href="https://twitter.com/ryanflorence"&gt;Ryan&amp;#x27;s&lt;/a&gt; doing
a tour to 12 cities in the US!!&lt;/li&gt;&lt;li&gt;&lt;a href="http://kcd.im/devtips"&gt;DevTips with Kent&lt;/a&gt; — I&amp;#x27;m still doing (week)daily
livestreams that hundreds of people watch :) Don&amp;#x27;t miss it!&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/confidently-shipping-code"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[React/JSX as a server-side templating language]]></title>
<description><![CDATA[Another note:
I've been teasing
about something big that I have coming. I'm totally not joking. I'm working on
something really huge and y'all will be the first to know about it. Stay
tuned. It's weeks away and I think you're going to love it. Last…]]></description>
<link>https://kentcdodds.com/blog/react-jsx-as-a-server-side-templating-language</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/react-jsx-as-a-server-side-templating-language</guid>
<pubDate>Mon, 01 Oct 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Another note:
&lt;a href="https://twitter.com/kentcdodds/status/1041712678970875904"&gt;I&amp;#x27;ve been teasing&lt;/a&gt;
about something big that I have coming. I&amp;#x27;m totally not joking. I&amp;#x27;m working on
something really huge and y&amp;#x27;all will be the first to know about it. Stay
tuned. It&amp;#x27;s weeks away and I think you&amp;#x27;re going to love it.&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Last week at PayPal, one of my pull requests was merged in an express codebase
which migrated us from a custom template system to using React function
components and JSX. The motivation was to reduce the maintenance overhead of
knowing and maintaining a custom template system in addition to the JSX we are
doing on the frontend.&lt;/p&gt;&lt;p&gt;The app is &lt;a href="https://paypal.me"&gt;paypal.me&lt;/a&gt;. The way it works is we have the
&lt;a href="https://www.paypal.me"&gt;home&lt;/a&gt;,
&lt;a href="https://www.paypal.com/paypalme/pages/terms"&gt;terms&lt;/a&gt;, and
&lt;a href="https://www.paypal.me/pages/countries"&gt;supported countries&lt;/a&gt; pages that are 100%
rendered HTML/CSS (and just a tiny bit of vanilla JS), and then the
&lt;a href="https://www.paypal.me/kentcdodds/10"&gt;profile&lt;/a&gt; and
&lt;a href="https://www.paypal.com/paypalme/my/profile"&gt;settings&lt;/a&gt; pages are rendered by the
server as &amp;quot;skeleton&amp;quot; html pages (with SEO-relevant tags and a root &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; etc.)
and then the client-side React app kicks in to load the rest of the
data/interactivity needed on the page.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;I should note that generally I&amp;#x27;d suggest that if you&amp;#x27;re doing any server
rendering at all, you&amp;#x27;d probably find better performance doing server
rendering for everything (using something like &lt;a href="https://nextjs.org"&gt;Next.js&lt;/a&gt;
or &lt;a href="https://www.gatsbyjs.org"&gt;gatsby&lt;/a&gt; if you can), not just the skeleton
&lt;code&gt;index.html&lt;/code&gt; as we&amp;#x27;re doing on &lt;a href="http://paypal.me"&gt;paypal.me&lt;/a&gt;. We have our
reasons (there&amp;#x27;s nuance in everything and I&amp;#x27;m not going to get into this).&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Before my PR, we actually had two systems in place. We used
&lt;a href="https://github.com/dondido/express-es6-template-engine"&gt;&lt;code&gt;express-es6-template-engine&lt;/code&gt;&lt;/a&gt;
for the profile and settings pages (which are actually the same page), and for
the marketing pages one of our engineers came up with a tagged-template literal
solution that was react-like (with functions that accepted props and returned a
string of HTML). So engineers that work on this codebase would have to know and
maintain:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;code&gt;express-es6-template-engine&lt;/code&gt; for the profile and settings pages&lt;/li&gt;&lt;li&gt;React and JSX for the client-side app&lt;/li&gt;&lt;li&gt;The custom tagged-template literal solution for the marketing pages.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;It was decided to simplify this down to a single solution: React and JSX for
both frontend and backend. And that&amp;#x27;s the task I took. I want to explain a few
of the gotchas and solutions that I ran into while making this transition.&lt;/p&gt;&lt;h3&gt;JSX compilation&lt;/h3&gt;&lt;p&gt;This was actually as easy as &lt;code&gt;npm install --save react react-dom&lt;/code&gt; in the
&lt;code&gt;server&lt;/code&gt;. Because &lt;a href="http://paypal.me"&gt;paypal.me&lt;/a&gt; uses
&lt;a href="https://kentcdodds.com/blog/tools-without-config"&gt;paypal-scripts&lt;/a&gt;, the server&amp;#x27;s already compiled with
the built-in babel configuration which will automatically add the necessary
react plugins if the project lists react as a dep. Nice! I LOVE Toolkits!&lt;/p&gt;&lt;h3&gt;HTML Structure&lt;/h3&gt;&lt;p&gt;The biggest challenge I faced with this involves integration with other PayPal
modules that generate HTML that need to be inserted into the HTML that we&amp;#x27;re
rendering. One such example of this is our polyfill service that
&lt;a href="https://kentcdodds.com/blog/polyfill-as-needed-with-polyfill-service"&gt;I wrote about a while back&lt;/a&gt;which
inserts a script tag that has some special query params and
&lt;a href="https://en.wikipedia.org/wiki/Cryptographic_nonce"&gt;a server nonce&lt;/a&gt;. We have
this as middleware and it adds a &lt;code&gt;res.locals.polyfill.headHTML&lt;/code&gt; which is a
string of HTML that needs to appear in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; that you render.&lt;/p&gt;&lt;p&gt;With the template literal and es6-template-engine thing we had, this was pretty
simple. Just add &lt;code&gt;${polyfill.headHTML}&lt;/code&gt; in the right place and you&amp;#x27;re set. In
React though, that&amp;#x27;s kinda tricky. Let&amp;#x27;s try it out. Let&amp;#x27;s assume that
&lt;code&gt;polyfill.headHTML&lt;/code&gt; is &lt;code&gt;&amp;lt;script src=&amp;quot;hello.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;. So if we do this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;&amp;lt;head&amp;gt;{polyfill.headHTML}&amp;lt;/head&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will result in HTML that looks like this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;&amp;lt;head&amp;gt;&amp;amp;lt;script src=&amp;amp;quot;hello.js&amp;amp;quot;&amp;amp;gt;&amp;amp;lt;/script&amp;amp;gt;&amp;lt;/head&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is because React escapes rendered interpolated values (those which appear
between &lt;code&gt;{&lt;/code&gt; and &lt;code&gt;}&lt;/code&gt;). This is a
&lt;a href="https://en.wikipedia.org/wiki/Cross-site_scripting"&gt;cross site-scripting (XSS)&lt;/a&gt;
protection feature built-into React. All of our apps are safer because React
does this. However, there are situations where it causes problems (like this
one). So React gives you an escape hatch where you can opt-out of this
protection. Let&amp;#x27;s use that:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;&amp;lt;head&amp;gt;
&amp;lt;div dangerouslySetInnerHTML={{__html: polyfill.headHTML}} /&amp;gt;
&amp;lt;/head&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So this would result in:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;&amp;lt;head&amp;gt;
&amp;lt;div&amp;gt;
&amp;lt;script src=&amp;quot;hello.js&amp;quot; /&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/head&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But that&amp;#x27;s not at all semantically accurate. A &lt;code&gt;div&lt;/code&gt; should not appear in a
&lt;code&gt;head&lt;/code&gt;. We also have some &lt;code&gt;meta&lt;/code&gt; tags. It technically works in Chrome, but I
don&amp;#x27;t know what would happen in all the browsers PayPal supports and I don&amp;#x27;t
want to bust SEO or functionality of older, less-forgiving browsers for this.&lt;/p&gt;&lt;p&gt;So here&amp;#x27;s the solution I came up with that I don&amp;#x27;t hate:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;&amp;lt;head&amp;gt;
&amp;lt;RawText&amp;gt;{polyfill.headHTML}&amp;lt;/RawText&amp;gt;
&amp;lt;/head&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The implementation of that &lt;code&gt;RawText&lt;/code&gt; component is pretty simple:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;function RawText({children}) {
return &amp;lt;raw-text dangerouslySetInnerHTML={{__html: children}} /&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So this will result in:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-html"&gt;&amp;lt;head&amp;gt;
&amp;lt;raw-text&amp;gt;
&amp;lt;script src=&amp;quot;hello.js&amp;quot; /&amp;gt;
&amp;lt;/raw-text&amp;gt;
&amp;lt;/head&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This doesn&amp;#x27;t solve the problem by itself. Here&amp;#x27;s what we do when we render the
page to HTML:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;const htmlOutput = ReactDOMServer.renderToStaticMarkup(&amp;lt;Page {...options} /&amp;gt;)
const rendered = `
&amp;lt;!DOCTYPE html&amp;gt;
${removeRawText(htmlOutput)}
`
// ...etc...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That &lt;code&gt;removeRawText&lt;/code&gt; function is defined right next to the &lt;code&gt;RawText&lt;/code&gt; component
and looks like this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;function removeRawText(string) {
return string.replace(/&amp;lt;\/?raw-text&amp;gt;/g, &amp;#x27;&amp;#x27;)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So, effectively what our &lt;code&gt;rendered&lt;/code&gt; string looks like is this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-html"&gt;&amp;lt;head&amp;gt;
&amp;lt;script src=&amp;quot;hello.js&amp;quot; /&amp;gt;
&amp;lt;/head&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;🎉 Cool right?&lt;/p&gt;&lt;p&gt;So we have a simple component we can use for any raw string we want inserted
as-is into the document without having to add an extra meaningless (and
sometimes semantically harmful) DOM node in the mix. (Note, the real solution to
this problem would be for React to
&lt;a href="https://github.com/facebook/react/issues/12014"&gt;support&lt;/a&gt;
&lt;a href="https://github.com/facebook/react/issues/12014"&gt;&lt;code&gt;dangerouslySetInnerHTML&lt;/code&gt;&lt;/a&gt;
&lt;a href="https://github.com/facebook/react/issues/12014"&gt;on Fragments&lt;/a&gt;).&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; The fact that this logic lives in a function right next to the
definition of the &lt;code&gt;RawText&lt;/code&gt; component rather than just hard-coding the
replacement where it happens is IMPORTANT. Anyone coming to the codebase and
seeing &lt;code&gt;RawText&lt;/code&gt; or &lt;code&gt;removeRawText&lt;/code&gt; will be able to find out what&amp;#x27;s going on
much more quickly.&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;h3&gt;Localization&lt;/h3&gt;&lt;p&gt;In our client-side app, we use a localization module that my friend Jamund and I
worked on that relies on a singleton &amp;quot;store&amp;quot; of content strings. It works great
because there&amp;#x27;s only one locale that&amp;#x27;ll ever be needed through the lifetime of
the client-side application. Singletons don&amp;#x27;t work very well on the backend
though. So I built a simple React Context consumer and provider which made it
easier to get messages using this same abstraction without the singleton. I&amp;#x27;m
not going to share the code for it, but here&amp;#x27;s how you can use it:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;&amp;lt;Message msgKey=&amp;quot;marketing_pages/new_landing.title&amp;quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It worked out pretty well. The &lt;code&gt;Message&lt;/code&gt; component renders the &lt;code&gt;MessageConsumer&lt;/code&gt;
component which will get the content out of context and retrieve the message
with the given key.&lt;/p&gt;&lt;h3&gt;Other things of note:&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://reactjs.org/docs/fragments.html"&gt;&lt;code&gt;React.Fragments&lt;/code&gt;&lt;/a&gt; are everywhere.
When the structure matters so much, you find yourself using React fragments
all over the place. We&amp;#x27;re using babel 7 and loving the new shorter syntax of
&lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;/&amp;gt;&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;style&lt;/code&gt;/&lt;code&gt;className&lt;/code&gt; changes. Before this was straightup HTML, the biggest
changes I had to make was all the &lt;code&gt;class=&amp;quot;&lt;/code&gt;had to be changed to &lt;code&gt;className=&amp;quot;&lt;/code&gt;
which wasn&amp;#x27;t all that challenging, but I found myself forgetting the
&lt;code&gt;style=&amp;quot;&lt;/code&gt;attributes needing to be changed to &lt;code&gt;style={&lt;/code&gt; and object syntax all
the time. Luckily React gives you a warning if you miss one :)&lt;/li&gt;&lt;li&gt;&lt;code&gt;${&lt;/code&gt; needed to be changed to &lt;code&gt;{&lt;/code&gt;. I found a few stray &lt;code&gt;$&lt;/code&gt; rendered several
times in the course of this refactor 😅&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;I&amp;#x27;m pretty pleased that we now only have one templating solution for the entire
app (both frontend and backend). I think that&amp;#x27;ll reduce the maintenance burden
of the app and that&amp;#x27;s a real win. Trying things out and doing experiments is a
good thing, but circling back to refactor things to the winning abstraction is
an important step to making applications that are maintainable for the
long-term. I hope this is helpful to you! Good luck!&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Learn more about React from me&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://kcd.im/beginner-react"&gt;The Beginner&amp;#x27;s Guide to React&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://kcd.im/advanced-react"&gt;Advanced React Component Patterns&lt;/a&gt; (also on
&lt;a href="https://frontendmasters.com/courses/advanced-react-patterns"&gt;Frontend Masters&lt;/a&gt;).&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://youtu.be/SAIdyBFHfVU?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;The introduction to React you&amp;#x27;ve been missing&lt;/a&gt; — My
talk from UtahJS Conf 2018. Lots of livecoding here. In this talk I teach
React from scratch in a single index.html file with no magic up my sleeves. We
start with a basic Hello World in vanilla JavaScript and incrementally iterate
through React APIs and JSX. We continue with introducing more of React&amp;#x27;s APIs.
&lt;a href="https://youtube.com/playlist?list=PLuVqdWOQ-PNn_lDYUVgcA4e91qxJzipva"&gt;Watch all the talks from UtahJS Conf 2018&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtube.com/playlist?list=PLV5CVI1eNcJhU1eyqkTjR0B5P7PzMVubB"&gt;Testing React Components @ PayPal 2018–09&lt;/a&gt; — I
gave a ~4 hour workshop at PayPal last week and livestreamed it.
&lt;a href="https://github.com/kentcdodds/react-testing-library-course/tree/workshop-2018-09"&gt;Here&amp;#x27;s the material&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/react-jsx-as-a-server-side-templating-language"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[How I am so productive]]></title>
<description><![CDATA[I get asked about this at least twice a week, so I thought I'd save myself some
time by writing a blog post I can reference instead of answering the same
question repeatedly (spoiler, this is one of my secrets). To help give you context, here are…]]></description>
<link>https://kentcdodds.com/blog/how-i-am-so-productive</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/how-i-am-so-productive</guid>
<pubDate>Mon, 24 Sep 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;I get asked about this at least twice a week, so I thought I&amp;#x27;d save myself some
time by writing a blog post I can reference instead of answering the same
question repeatedly (spoiler, this is one of my secrets).&lt;/p&gt;&lt;p&gt;To help give you context, here are some of the things I do on a fairly regular
basis these days:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;I teach Sunday school to ~6 nine-year-old kids (we&amp;#x27;re going through the
&lt;a href="https://www.mormon.org/free-bible"&gt;Old Testament&lt;/a&gt; this year). In addition to
attending 3 hours of church, I also prepare and deliver a one hour lesson for
them every other week.&lt;/li&gt;&lt;li&gt;On Sundays I generally don&amp;#x27;t commit any code or do any &amp;quot;work.&amp;quot; I have church
and family time and responsibilities (though I do enjoy spending the evening
with
&lt;a href="https://twitter.com/craigwalker1123/status/1039138835714560000"&gt;new friends playing Dominion&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;On Mondays, I publish the blogpost newsletter from two weeks ago to
&lt;a href="http://kentcdodds.com/blog"&gt;kentcdodds.com/blog&lt;/a&gt;, a new one for subscribers.
(~1.5 hours of work, depending...)&lt;/li&gt;&lt;li&gt;Product tasks (currently helping work on &lt;a href="https://paypal.me"&gt;paypal.me&lt;/a&gt;) (this
is normally where most of my weekday is spent)&lt;/li&gt;&lt;li&gt;Attend work meetings&lt;/li&gt;&lt;li&gt;Help people on slack/video chat&lt;/li&gt;&lt;li&gt;Work on &lt;a href="https://kentcdodds.com/blog/tools-without-config"&gt;paypal-scripts&lt;/a&gt; (among other internal
libraries and tools)&lt;/li&gt;&lt;li&gt;traveling/training (about once a quarter. I&amp;#x27;m on an airplane right now for
such an engagement)&lt;/li&gt;&lt;li&gt;Research, prepare, and do a
&lt;a href="http://kcd.im/devtips"&gt;DevTips with Kent livestream&lt;/a&gt; (~20 minutes...
sometimes) (week-daily)&lt;/li&gt;&lt;li&gt;Respond to literally dozens of GitHub issues/PRs (daily)&lt;/li&gt;&lt;li&gt;Code up or help people code up solutions to the GitHub issues&lt;/li&gt;&lt;li&gt;Release ~5 of any of my &amp;gt;100 npm modules multiple times a day&lt;/li&gt;&lt;li&gt;Travel to (sometimes) and speak at a conference (about once or twice a month)&lt;/li&gt;&lt;li&gt;Travel to (sometimes) and deliver a 1–2 day workshop on one of five topics I
regularly train about.&lt;/li&gt;&lt;li&gt;Record &lt;a href="http://egghead.io"&gt;egghead.io&lt;/a&gt; lessons and courses (working on some of
this very hard core right now)&lt;/li&gt;&lt;li&gt;Research and prepare educational material (for
talks/workshops/courses/devtips/etc.)&lt;/li&gt;&lt;li&gt;Go out to lunch with a (new) friend in the community about once a week&lt;/li&gt;&lt;li&gt;Outline and prepare for writing my novel for
&lt;a href="https://nanowrimo.org"&gt;NaNoWriMo&lt;/a&gt; (which is going to be epic by the way).&lt;/li&gt;&lt;li&gt;&lt;a href="http://kcd.im/ama"&gt;AMA&lt;/a&gt;: Ask Me Anything (currently has 475 questions I&amp;#x27;ve
answered).&lt;/li&gt;&lt;li&gt;&lt;a href="http://kcd.im/tech-chats"&gt;TechChats&lt;/a&gt;: livestream video chats with people
about tech (about once a month or so).&lt;/li&gt;&lt;li&gt;Publish a 3 minute podcast (on &lt;a href="http://kcd.im/3-mins"&gt;3 minutes with Kent&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;Be a guest on podcasts (about once a month or so).&lt;/li&gt;&lt;li&gt;Respond to literally dozens of questions per day coming from Tweets (mostly),
Twitter DMs (several daily), Slack, email, YouTube comments, and pigeon (one
of those is a joke).&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;On top of all that, I&amp;#x27;m married, have 4 kids (6 and younger) and a puppy, and
have a home and yard/garden to care for.&lt;/p&gt;&lt;h3&gt;A typical day&lt;/h3&gt;&lt;p&gt;Let me share a fairly general weekday with you:&lt;/p&gt;&lt;p&gt;Normally I wake up at ~7:00 AM and I&amp;#x27;m ready for work by ~9:00 AM. I sit at my
desk (I work from home) and start with my daily scripture study for a few
minutes. Then I power on the computer, and start with my email and twitter (the
stuff I hadn&amp;#x27;t addressed while brushing my teeth etc. 😅). If I&amp;#x27;m aware of any
pressing work, I&amp;#x27;ll take care of that first. If it&amp;#x27;s Monday, I&amp;#x27;ll make sure my
blog post is published, then start working on this week&amp;#x27;s blogpost newsletter.
Then I do the DevTips with Kent livestream.&lt;/p&gt;&lt;p&gt;By this time it&amp;#x27;s normally ~10:00 AM (or later on Mondays/if there&amp;#x27;s pressing
work I had to do first). It&amp;#x27;s likely that I&amp;#x27;ve already released one or two new
versions of my npm modules, answered a half dozen questions, and
responded/reviewed several GitHub issues/PRs. Now I start on whatever PayPal
product work I&amp;#x27;m working on (as I mentioned, I&amp;#x27;m helping with
&lt;a href="https://paypal.me"&gt;paypal.me&lt;/a&gt; right now). I meet with my co-workers and decide
the highest priority tasks and get to work on them.&lt;/p&gt;&lt;p&gt;At ~12:00 PM (often later if I&amp;#x27;m really involved in something), I go up and have
lunch with my family. If he&amp;#x27;s not already in bed, I read a book to one of my
boys and put him down for a nap (working from home is the best). My lunch break
is normally ~30 minutes.&lt;/p&gt;&lt;p&gt;I spend the afternoon working on more PayPal stuff, meetings, helping answer
questions from all the various channels (and sadly ignoring many of them as I
have work to do), and releasing more versions of various OSS libraries/tools.&lt;/p&gt;&lt;p&gt;I wrap up the day between 5:00 PM and 6:00 PM and head upstairs. It&amp;#x27;s family
time. Often I&amp;#x27;ll hang out with my wife after the kids are in bed. Sometimes
though, if I&amp;#x27;m working on a big course for &lt;a href="http://egghead.io"&gt;egghead.io&lt;/a&gt; or
something, I&amp;#x27;ll go back to my office and start working on that. Normally I&amp;#x27;ll go
to bed before 11:00 PM.&lt;/p&gt;&lt;p&gt;Saturdays are mostly yard work and family time. I don&amp;#x27;t &lt;em&gt;normally&lt;/em&gt; do much
coding on Saturdays. Sundays are family and church time. I very rarely do any
work on Sundays (occasionally I&amp;#x27;ll merge simple PRs from my phone or get a head
start on this newsletter).&lt;/p&gt;&lt;p&gt;If this schedule sounds set in stone or a solid routine, let me assure you it&amp;#x27;s
not. What I&amp;#x27;ve written is a pretty general schedule that wasn&amp;#x27;t really planned
and is just what kinda happened. In any case, I hope it helps to frame the rest
of my advice in a way that&amp;#x27;s relatable and helpful to you.&lt;/p&gt;&lt;h3&gt;It&amp;#x27;s an illusion&lt;/h3&gt;&lt;p&gt;If you read carefully, you&amp;#x27;ll notice that I do a bunch of my stuff when I&amp;#x27;m on
the clock at PayPal. That&amp;#x27;s because the stuff I do is good for PayPal and my
bosses have appreciated that I do it. Just last week I had multiple different
engineers within PayPal thank me for the daily
&lt;a href="http://kcd.im/devtips"&gt;DevTips with Kent&lt;/a&gt; livestreams and
&lt;a href="http://kcd.im/news"&gt;these newsletters&lt;/a&gt;. PayPal is happy that I&amp;#x27;m sharing my
knowledge and so long as what I share is not proprietary/legally concerning/etc,
they&amp;#x27;re happy to let me continue doing that. (You could say this newsletter is
sponsored by PayPal! Thanks PayPal!).&lt;/p&gt;&lt;p&gt;PayPal employees also use a bunch of the open source software that I maintain.
So when I&amp;#x27;m doing work on my open source projects during work hours, 90% of the
time it&amp;#x27;s because we have a problem within PayPal that needs solving and I&amp;#x27;m
just doing my job to make PayPal engineers more effective. Some of my projects
are libraries that I created at PayPal and then open sourced while others are
projects I created outside of my time at PayPal and now PayPal engineers use. In
either case, working on those projects (and contributing to other projects of
which I&amp;#x27;m not a maintainer), is all part of my job.&lt;/p&gt;&lt;p&gt;So when people ask me: &amp;quot;HOW DO YOU DO ALL THIS STUFF &lt;em&gt;AND&lt;/em&gt; HAVE A JOB AT
PAYPAL!?&amp;quot; My answer is: &amp;quot;well... a lot of this stuff &lt;em&gt;is&lt;/em&gt; my job at PayPal.&amp;quot;&lt;/p&gt;&lt;p&gt;This brings me to my next point:&lt;/p&gt;&lt;h3&gt;Increase the impact of your value&lt;/h3&gt;&lt;p&gt;We&amp;#x27;re all constantly creating value in the world. A conversation with your
co-worker over lunch about why, what, and how to do a git rebase is creating
value. A meetup talk you&amp;#x27;re delivering is creating value. etc. etc. etc. The
secret that I&amp;#x27;ve found is taking the value that you&amp;#x27;re already creating, and
increase its impact by preserving and presenting it to the world.&lt;/p&gt;&lt;p&gt;So turn that conversation into a blog post or have that conversation over Google
Hangouts on Air and have it upload to YouTube automatically (which is what my
&lt;a href="http://kcd.im/tech-chats"&gt;tech chats&lt;/a&gt; are). Make sure your meetup talk is
recorded (even if that means you&amp;#x27;re just recording your screen, which I do all
the time). Instead of answering your co-worker&amp;#x27;s slack question about arrow
functions on slack, type it out as a quick blog post on medium, a gist, or a 🔥
FIRE 🔥 TWEET 🔥 and send them the link.&lt;/p&gt;&lt;p&gt;As long as your company is cool with you sharing non-proprietary knowledge with
the world, then take advantage of that (as a side note, I would have a very hard
time being successful at a company which does not value open knowledge sharing
like this. I know it&amp;#x27;s a privilege to work at a company like PayPal. Sorry if
you&amp;#x27;re not in an environment like PayPal in this way.)&lt;/p&gt;&lt;p&gt;In short &lt;a href="https://twitter.com/swyx/status/1009174159690264579"&gt;learn in public&lt;/a&gt;
(I love you &lt;a href="https://twitter.com/swyx"&gt;Shawn!&lt;/a&gt;). It&amp;#x27;s likely that if you listed
out all the things you do in a week your list would be just as long if not
longer than mine. The thing that makes it appear that I am so productive is that
I make public as much of what I do as possible.&lt;/p&gt;&lt;h3&gt;Automation&lt;/h3&gt;&lt;p&gt;If you maintain an npm package, it may surprise you (or you may be skeptical of
the fact) that I manage to release multiple versions of multiple packages in a
typical day. Believe me though, I release almost every PR made on my open source
projects within minutes of my merging them into &lt;code&gt;master&lt;/code&gt;, and often I do so from
my phone.&lt;/p&gt;&lt;p&gt;This is possible because my open source projects have a solid suite of tests
that run in CI and give me confidence things are working followed by an
automation script that publishes to npm and generates a GitHub changelog. For
years I&amp;#x27;ve been using an awesome tool called
&lt;a href="https://github.com/semantic-release/semantic-release"&gt;semantic-release&lt;/a&gt;
(shoutout to
&lt;a href="https://github.com/semantic-release/semantic-release/blob/caribou/README.md#team"&gt;the team of fantastic humans&lt;/a&gt;)
to automatically release my packages.&lt;/p&gt;&lt;p&gt;The concept of automation is something
&lt;a href="https://kentcdodds.com/blog/automation"&gt;I&amp;#x27;ve written about in the past&lt;/a&gt;. It&amp;#x27;s how I got into software
development and I feel strongly that automation is the way we can make ourselves
more productive
(&lt;a href="https://xkcd.com/1205"&gt;even if it takes longer to develop the automation than the time it would save us&lt;/a&gt;).
If you find yourself repeatedly doing a task, see if there&amp;#x27;s a simple way to
automate it. (Like
&lt;a href="https://github.com/kentcdodds/hive-api"&gt;what I do for creating my kcd.im/ short urls&lt;/a&gt;
+
&lt;a href="https://github.com/kentcdodds/dotfiles/blob/94c00b43354f86595647f9ff18057ff9e6469d33/.bash_profile#L61-L63"&gt;shorten&lt;/a&gt;
😄, which happens to be another form of automation and productivity boost
because short URLs are easier/faster to give to people, and people remember them
better).&lt;/p&gt;&lt;h3&gt;Enable others&lt;/h3&gt;&lt;p&gt;Many of those releases of my open source projects I do are releasing code that I
did not write. I put forth an investment of time in helping
&lt;a href="http://kcd.im/pull-request"&gt;and teaching&lt;/a&gt; other people contribute to my
projects and &lt;a href="https://github.com/all-contributors/all-contributors"&gt;do things&lt;/a&gt;
to help motivate people to do so. This means that I&amp;#x27;m able to do more because
other people handle a lot of project maintenance for me so I can do other
things.&lt;/p&gt;&lt;h3&gt;Don&amp;#x27;t answer the same question twice&lt;/h3&gt;&lt;p&gt;I learned early on that people ask me repeat questions early on. I like to give
them answers, but I also found out quickly that
&lt;a href="http://kcd.im/no-time"&gt;I don&amp;#x27;t have time to answer everyone&lt;/a&gt; and it&amp;#x27;s a bit
frustrating to answer the same question multiple times. This is why having
&lt;a href="https://kentcdodds.com/blog"&gt;an active blog&lt;/a&gt; and &lt;a href="http://kcd.im/ama"&gt;an AMA&lt;/a&gt; are super helpful.&lt;/p&gt;&lt;p&gt;If someone asks me a question, 99% of the time I&amp;#x27;ll ask them to ask it on my
AMA. If I get the same question many times, then I&amp;#x27;ll make it the subject of a
DevTip or blog. Having multiple places/formats I can go to answer people&amp;#x27;s
questions in public does four things:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Allows me to answer their question&lt;/li&gt;&lt;li&gt;Allows others to see that answer (increases the impact of the value I&amp;#x27;m
creating)&lt;/li&gt;&lt;li&gt;Gives me motivation to give them a higher quality answer.&lt;/li&gt;&lt;li&gt;Gives me a link to share with the next person who asks (which is way faster
than writing it out again)&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;I guess it also contributes to the illusion that I&amp;#x27;m doing more and I&amp;#x27;m more
productive. I&amp;#x27;m sure you answer a lot of questions as well, but how does anyone
know if you don&amp;#x27;t share?&lt;/p&gt;&lt;h3&gt;Avoiding Burnout&lt;/h3&gt;&lt;p&gt;When I tweeted that this would be the subject of today&amp;#x27;s newsletter, my good
friend &lt;a href="https://twitter.com/markdalgleish"&gt;Mark Dalgleish&lt;/a&gt;
&lt;a href="https://twitter.com/markdalgleish/status/1038922626826031104"&gt;responded&lt;/a&gt;:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Because you haven&amp;#x27;t burned out yet?&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I honestly don&amp;#x27;t think that I&amp;#x27;ve ever truly burned out. I&amp;#x27;ve only been doing
this software thing professionally for ~4 years, so maybe that&amp;#x27;s why. I&amp;#x27;ve
definitely burned out on specific projects or frameworks, but I&amp;#x27;ve generally
been able to keep moving and doing things that keep me excited and provide value
to the world while taking care of myself and my relationships.&lt;/p&gt;&lt;p&gt;I should probably do this subject better justice in another blog post, but I&amp;#x27;ll
just say that in general what I do to avoid burnout is to not do stuff I don&amp;#x27;t
have to do or want to do. I&amp;#x27;ve learned and internalized that I don&amp;#x27;t owe anyone
anything unless I&amp;#x27;ve made an actual commitment of marriage/employment/etc. So
while I try to be kind and helpful, at the end of the day if I can&amp;#x27;t help, then
I don&amp;#x27;t and I don&amp;#x27;t stress over it.&lt;/p&gt;&lt;p&gt;For example, there are many open issues on my GitHub projects that get no
response from me because I&amp;#x27;ve chosen to give my time to other things I&amp;#x27;d rather
do. I do feel bad I can&amp;#x27;t do more, but I don&amp;#x27;t stress over it.&lt;/p&gt;&lt;p&gt;This subject isn&amp;#x27;t all that simple, but that&amp;#x27;s all I have time for (and I&amp;#x27;m not
going to stress over not giving you more because I don&amp;#x27;t owe you anything 😜
#seewhatididthere).&lt;/p&gt;&lt;h3&gt;Hyper-focused&lt;/h3&gt;&lt;p&gt;I&amp;#x27;ve listed pretty much everything I do. You may have noticed that I don&amp;#x27;t have
many hobbies. This is true. I have a few things that I do for fun, but it pretty
much all boils down to: Family, Religion, and Coding.&lt;/p&gt;&lt;p&gt;Even though this is working out so far, I don&amp;#x27;t believe this is sustainable.
This is one reason why I&amp;#x27;m so excited about writing this novel for
&lt;a href="https://nanowrimo.org"&gt;NaNoWriMo&lt;/a&gt;. It&amp;#x27;ll be a new creative outlet. And
hopefully by November I&amp;#x27;ll be done with most of
&lt;a href="https://twitter.com/kentcdodds/status/1038584983990849536"&gt;the HUGE things I&amp;#x27;m working&lt;/a&gt;
on so I can dedicate myself to writing 50,000 words in 30 days :)&lt;/p&gt;&lt;p&gt;That said, I think short bursts of hyper-focus do help me get a lot done.
Whether I&amp;#x27;m hyper-focused on an &lt;a href="http://egghead.io"&gt;egghead.io&lt;/a&gt; course, or
getting something specific done at work, it helps me get things done. I&amp;#x27;m not
sure how to explain it, but for me hyper-focus means that I kinda don&amp;#x27;t think
about anything else for a while. When I&amp;#x27;m not with my family or fulfilling
another commitment, I&amp;#x27;m thinking about and working on this thing until it&amp;#x27;s
done.&lt;/p&gt;&lt;p&gt;I didn&amp;#x27;t explain that well and should probably remove this section, but I&amp;#x27;m not
gonna. Maybe it&amp;#x27;ll be helpful for someone.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Continued:&lt;/strong&gt; Turns out this was helpful to a few people so I thought I&amp;#x27;d
expound on this a tiny bit (and my wife suggested that I do as well because she
thinks this makes a significant impact on who I am (not necessarily that it&amp;#x27;s a
desirable trait).&lt;/p&gt;&lt;p&gt;So this necessarily isn&amp;#x27;t a short-term kind of thing, it doesn&amp;#x27;t prevent me from
sleeping well at night (though sometimes I do have trouble shutting my brain
off, most of the time I sleep fine). This also isn&amp;#x27;t the same as staying focused
an on-task during a period of several hours when I&amp;#x27;m trying to get something
done (something that I&amp;#x27;m typically not very good at doing unless I&amp;#x27;m &lt;em&gt;very&lt;/em&gt;
excited about it).&lt;/p&gt;&lt;p&gt;This hyper-focus is pretty much that I immerse myself in the subject for a
period of time. As an example, since I decided that I want to write this novel a
few weeks ago, I&amp;#x27;ve found a TON of content online about tools novel writers use
to make their books &amp;quot;work&amp;quot; and I&amp;#x27;ve been consuming it at a rapid rate. It&amp;#x27;s
filled my idle mind. I&amp;#x27;m still able to turn my attention to my family, my work,
or courses that I&amp;#x27;m working on, but when I&amp;#x27;m doing mundane tasks and my brain is
able to think freely, it&amp;#x27;s consumed by the idea of the novel itself and learning
tools that I can apply when I start writing it in November. Ask my wife. If
we&amp;#x27;re not talking about something that&amp;#x27;s actually important, then I&amp;#x27;ll
inevitably turn the conversation over to the book (and she&amp;#x27;s been
&lt;a href="https://twitter.com/kentcdodds/status/1043712163490160640"&gt;extremely helpful&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;I don&amp;#x27;t have tips of how you can develop this in yourself, and I&amp;#x27;m not even sure
that I would recommend it. It&amp;#x27;s just something that I do that my wife and I
think may have something to do with my productivity.&lt;/p&gt;&lt;h3&gt;Spend more time producing than consuming&lt;/h3&gt;&lt;p&gt;I do not spend a lot of time watching other people&amp;#x27;s courses or reading other
people&amp;#x27;s blogs/newsletters. I definitely will skim blog posts as needed, or I&amp;#x27;ll
sit down and watch a few &lt;a href="http://egghead.io"&gt;egghead.io&lt;/a&gt; lessons or part of a
Frontend Master&amp;#x27;s course when there&amp;#x27;s something specific I need to learn. I love
&lt;a href="https://gedd.ski"&gt;Dave Geddes&amp;#x27;s&lt;/a&gt; mastery games on
&lt;a href="https://www.gridcritters.com"&gt;CSS grid&lt;/a&gt; and
&lt;a href="https://flexboxzombies.com/p/flexbox-zombies"&gt;Flexbox&lt;/a&gt;, but generally I spend a
bunch more time working on producing my own material/projects. I think that
makes me more productive as well.&lt;/p&gt;&lt;h3&gt;The importance of balance&lt;/h3&gt;&lt;p&gt;With all this talk of productivity, I should probably mention that I&amp;#x27;ve learned
that it&amp;#x27;s important to live a balanced life. Like I said, I can get pretty
focused on one thing, but I spend a lot of time with my family and that brings
me joy. Shutting down for a little bit, taking a step back, and &lt;strong&gt;working on
your relationships&lt;/strong&gt; is where you&amp;#x27;ll get your juice to keep going.&lt;/p&gt;&lt;p&gt;So &lt;strong&gt;the fact that I&amp;#x27;m married and have four kids and a dog isn&amp;#x27;t a detriment to
my productivity,&lt;/strong&gt; but really &lt;em&gt;it&amp;#x27;s an important part of my secret to
productivity.&lt;/em&gt; They motivate me and recharge me in ways that I couldn&amp;#x27;t
understand before I had them in my life.&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;So the reasons it appears I&amp;#x27;m so productive is multi-facited:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Lots of it is an illusion&lt;/li&gt;&lt;li&gt;I&amp;#x27;m privileged to work at a place that values open knowledge sharing and
doesn&amp;#x27;t limit what I do in my free time&lt;/li&gt;&lt;li&gt;I learn in public, thereby increasing the impact of the value that I create.&lt;/li&gt;&lt;li&gt;I automate mundane/time consuming/context switching tasks&lt;/li&gt;&lt;li&gt;I answer questions in a public forum&lt;/li&gt;&lt;li&gt;I spend more time producing that consuming&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I should say also that my wife plays a &lt;strong&gt;huge&lt;/strong&gt; role in how I&amp;#x27;m so productive.
However, she is a pretty private person and asked that I not talk about her much
publicly (except she did give me permission to say this). I couldn&amp;#x27;t do all of
the things I do if it weren&amp;#x27;t for her.&lt;/p&gt;&lt;p&gt;I don&amp;#x27;t want to give the false impression that I only &lt;em&gt;appear&lt;/em&gt; productive
either. I really do feel like I&amp;#x27;m quite productive. But hopefully this makes my
productivity more realistic and attainable in your mind. I hope some of these
ideas help inspire you to be more productive and more importantly find more
happiness through your relationships. Good luck!&lt;/p&gt;&lt;p&gt;Subscribe to my newsletter below to get content like this delivered to your
inbox two weeks before it&amp;#x27;s published to my blog:&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Learn more about career development from me&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/blog/why-and-how-i-started-public-speaking"&gt;Why and How I started public speaking&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://buttondown.email/kentcdodds/archive/03761505-8609-404c-a5b7-5367013292bf"&gt;Getting Noticed and Widening Your Reach&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/-qPh6I2hfjw?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;Zero to 60 in Software Development: How to Jumpstart Your Career — Forward 4 Web Summit&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://medium.com/@sachagreif/take-the-state-of-javascript-2018-survey-c43be2fcaa9"&gt;Take the State of JavaScript 2018 Survey!&lt;/a&gt; — And
make sure to add react-testing-library in the &amp;quot;other&amp;quot; field for &amp;quot;testing
tools.&amp;quot; If they can add enzyme, then they should have react-testing-library as
well!&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.ageekleader.com/agl-059-kent-c-dodds"&gt;A Geek Leader 059: Kent C. Dodds&lt;/a&gt; — On
this podcast I talk about my career story and stuff! Should be interesting if
you thought this blog post was interesting :)&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/mattphillips/jest-expect-message"&gt;jest-expect-message&lt;/a&gt; by
&lt;a href="https://twitter.com/mattphillipsio"&gt;Matt Phillips&lt;/a&gt;: Add custom message to
Jest expects 🃏🗯&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/jest-community/jest-extended"&gt;jest-extended&lt;/a&gt;: Additional
Jest matchers 🃏💪&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/how-i-am-so-productive"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Getting Noticed and Widening Your Reach]]></title>
<description><![CDATA[This last week I had three people complaining to me (in individual interactions)
that they create cool things, but what they create is not noticed because they
don't have a following on Twitter or otherwise. In at least one of the cases
there was a…]]></description>
<link>https://kentcdodds.com/blog/getting-noticed-and-widening-your-reach</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/getting-noticed-and-widening-your-reach</guid>
<pubDate>Mon, 17 Sep 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;This last week I had three people complaining to me (in individual interactions)
that they create cool things, but what they create is not noticed because they
don&amp;#x27;t have a following on Twitter or otherwise. In at least one of the cases
there was a fair amount of bitterness. An attitude of: &amp;quot;If you create something
it becomes popular by virtue of you being so popular. If I create something, it
goes unnoticed even if it&amp;#x27;s better than what you created.&amp;quot;&lt;/p&gt;&lt;p&gt;While this may be true, the attitude bothers me. I&amp;#x27;d be classified in the
&amp;quot;popular&amp;quot; crowed, so maybe that&amp;#x27;s why it bothers me, but it also bothers me
because it feels like
&lt;a href="https://www.lds.org/general-conference/1989/04/beware-of-pride"&gt;&amp;quot;pride from the bottom looking up&amp;quot;&lt;/a&gt;
or could also come from
&lt;a href="https://mindsetonline.com/whatisit/about"&gt;a fixed mindset&lt;/a&gt;. I wasn&amp;#x27;t born with
a twitter following (though I was born into privilege which makes a non-trivial
impact, and I&amp;#x27;ll address that later). I worked for this by creating things and
doing things to get noticed even before I had the following. This is true of
most people with a wide reach. In today&amp;#x27;s newsletter, I&amp;#x27;d like to share with you
some things that I&amp;#x27;ve seen be an effective way to get your work noticed and
widen your reach.&lt;/p&gt;&lt;p&gt;There&amp;#x27;s not one thing I&amp;#x27;ve done to get noticed and widen my reach. And there&amp;#x27;s
also not a sequence. It&amp;#x27;s been a mix of several things (including hard work,
luck, timing, and kindness of others) that have helped me to do this. Depending
on what you&amp;#x27;re trying to get noticed for, there are different things you can do,
so I&amp;#x27;ll focus on a few and hopefully that&amp;#x27;ll touch on what you&amp;#x27;re doing...&lt;/p&gt;&lt;h3&gt;&lt;a href="https://github.com/kentcdodds"&gt;Open source&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:800px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/1ac7db0cd66099506485ca721862a6dd/a296c/typing.jpg" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:66.625%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="a person touch typing on a laptop" title="a person touch typing on a laptop" src="https://kentcdodds.com/static/1ac7db0cd66099506485ca721862a6dd/a296c/typing.jpg" srcSet="https://kentcdodds.com/static/1ac7db0cd66099506485ca721862a6dd/d2274/typing.jpg 259w,https://kentcdodds.com/static/1ac7db0cd66099506485ca721862a6dd/34151/typing.jpg 518w,https://kentcdodds.com/static/1ac7db0cd66099506485ca721862a6dd/a296c/typing.jpg 800w" sizes="(max-width: 800px) 100vw, 800px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;h3&gt;&lt;a href="https://github.com/kentcdodds/genie"&gt;geniejs 🧞‍&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;My first personal open source project that I wanted to get noticed was
&lt;a href="https://github.com/kentcdodds/genie"&gt;geniejs&lt;/a&gt;.
&lt;a href="https://github.com/kentcdodds/genie/commit/18db942457d8e7855a3afbb7345e9f8aa5c5a8ce"&gt;The first commit&lt;/a&gt;
was back in 2013. I can&amp;#x27;t remember exactly how many followers I had, but at the
time
&lt;a href="https://twitter.com/search?l=&amp;amp;q=from%3Akentcdodds%20since%3A2013-08-01%20until%3A2013-08-31&amp;amp;src=typd"&gt;I was tweeting&lt;/a&gt;
using &lt;a href="https://friendsplus.me"&gt;Friends+ me&lt;/a&gt; (because I thought Google+ was the
bomb) and of all my tweets that month, only one got a single favorite. Needless
to say, I wasn&amp;#x27;t well known or popular.&lt;/p&gt;&lt;p&gt;And honestly, my project didn&amp;#x27;t get super popular at the time either. However,
that didn&amp;#x27;t stop me from working on getting it noticed. I presented it at my
work&amp;#x27;s hack night around that time (it&amp;#x27;s actually
&lt;a href="https://github.com/kentcdodds/ama/issues/1"&gt;how I got my first fulltime job at Domo&lt;/a&gt;),
I built
&lt;a href="http://kentcdodds.github.io/genie/workshop"&gt;a sweet in-browser workshop&lt;/a&gt; and
used it in
&lt;a href="https://www.meetup.com/UtahJS-Orem-Meetup/events/156148202"&gt;my first meetup talk&lt;/a&gt;,
I then lucked out and got a conference (MidwestJS 2014) to accept me to give
that talk there (I only was able to speak because another speaker canceled).&lt;/p&gt;&lt;p&gt;Here are some takeaways from this experience: It never got very popular or
widely used (it&amp;#x27;s still not, despite my level of reach, though
&lt;a href="https://github.com/CompuIves/codesandbox-client/blob/76815f14c90e85c95c604624466fe2d50c995204/packages/app/src/app/pages/Sandbox/QuickActions/index.js"&gt;it is used by codesandbox!&lt;/a&gt;).
Despite this it gave me opportunities to improve my skills, show my skills, get
a job, and speak at a meetup and conference. This was primarily a combination of
luck, timing, assistance (my friend
&lt;a href="https://twitter.com/iammerrick"&gt;Merrick Christensen&lt;/a&gt; should be thanked for
helping me turn this into a job opportunity), courage (to propose my library as
the subject for a talk at a meetup and conference), and hard work/persistence (I
documented the library very well and built a great learning experience).&lt;/p&gt;&lt;h3&gt;&lt;a href="https://github.com/formly-js/angular-formly"&gt;angular-formly&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;About a year after I started work on geniejs (when I still did not have much by
way of a twitter following, etc.), I was moonlighting at a small startup that
had a pretty basic CRUD app with a TON of forms. I looked around at the
AngularJS form libraries, found one I really liked and before long
&lt;a href="https://github.com/formly-js/angular-formly/pull/17"&gt;I made my first pull request to angular-formly&lt;/a&gt;.
At the time, it wasn&amp;#x27;t a terribly popular project itself, but I needed it and it
satisfied most of my use cases.&lt;/p&gt;&lt;p&gt;In the weeks that followed I made more and more pull requests and before too
long, the project maintainer (who was no longer using the project) asked me if I
wanted to take the project over as the maintainer. I accepted and began the work
of improving the project and building a community.&lt;/p&gt;&lt;p&gt;Honestly, at the time I wasn&amp;#x27;t really thinking that&amp;#x27;s what I was doing. A lot of
my concern was the excitement of hearing that people were using something that I
built and a desire for my library to be the best in its class. Definitely not
the most pure motivations, but my results were positive and within a few months,
&lt;a href="https://npm-stat.com/charts.html?package=angular-formly&amp;amp;from=2015-01-01&amp;amp;to=2018-09-01"&gt;downloads quadrupled&lt;/a&gt;
and to my knowledge, angular-formly is still the number one most downloaded
AngularJS forms library.&lt;/p&gt;&lt;p&gt;So what did I do to build such popularity of the project so quickly? Well, one
thing I did (which I don&amp;#x27;t recommend) was I sorta sold my soul to the project. I
allowed myself to get carried away in answering issues as if they were paid
support requests. I prided myself on responding to issues in seconds and having
a fix pushed out in minutes. This was a lot of fun, but it did put strain on my
important relationships and my mental health, which is why I don&amp;#x27;t recommend it.&lt;/p&gt;&lt;p&gt;I&amp;#x27;ve found that you can build a strong and positive community without
sacrificing your well-being and relationships. That&amp;#x27;s a subject for another blog
post. Just know that working on building a community by
&lt;a href="https://twitter.com/kentcdodds/status/582620905433489408"&gt;creating fantastic documentation&lt;/a&gt;(including
&lt;a href="http://docs.angular-formly.com/docs/learn-angular-formly"&gt;several free egghead.io lessons&lt;/a&gt;),
&lt;a href="https://kentcdodds.com/blog/first-timers-only"&gt;encouraging contribution&lt;/a&gt;, and
&lt;a href="https://github.com/all-contributors/all-contributors"&gt;recognizing and trusting contributors&lt;/a&gt;
is an important part of getting adoption and recognition for your open source
work.&lt;/p&gt;&lt;p&gt;Other things that I did which were significant help were similar to what I did
with geniejs: I spoke at meetups and conferences (my talk at MidwestJS 2015 was
about angular-formly, and I gave the same talk at the first ng-nl conference). I
worked on making the documentation and learning materials fantastic. I ensured
the project satisfied the use cases it needed to while attempting to avoid
overcomplexity (so it was something people would &lt;em&gt;want&lt;/em&gt; to use). I also reached
out to &lt;em&gt;relevant&lt;/em&gt; newsletters to invite them to check it out and reference it in
their newsletter. Oh, and I tweeted about it
&lt;a href="https://twitter.com/search?q=from%3Akentcdodds%20formly&amp;amp;src=typd"&gt;a lot&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;It took a lot of work, but my work was recognized and appreciated and the
success there was a major talking point in my interview with my future boss&amp;#x27;s
boss at PayPal which probably helped me get hired.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Something I did NOT do&lt;/strong&gt; is spam dozens of &amp;quot;influencers&amp;quot; out of the blue on
twitter asking them to use and promote a library which for them was probably
irrelevant because they probably didn&amp;#x27;t need or have a use case for anyway. I
have dozens of people per week asking me to review the things they&amp;#x27;ve built or
written. This really only bothers me when it&amp;#x27;s clear that I&amp;#x27;m one of tens of
others to whom they&amp;#x27;ve sent the same message, but it&amp;#x27;s also ineffective because
often these &amp;quot;influencers&amp;quot; either don&amp;#x27;t have the time to review them or the
project may not have any relevance to them.&lt;/p&gt;&lt;p&gt;I also did &lt;em&gt;not&lt;/em&gt; attempt to throw shade at alternatives or downplay the value of
their abstractions. Being unkind to the hard work of other people is a very poor
way to promote your project and has no good place in the world.&lt;/p&gt;&lt;h3&gt;&lt;a href="https://kentcdodds.com/talks"&gt;Speaking&lt;/a&gt; &amp;amp; &lt;a href="https://kentcdodds.com/workshops"&gt;Teaching&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:800px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/127992efad005a7454c557a8815c4162/a296c/0.jpg" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:66.625%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="me teaching people at a workshop" title="me teaching people at a workshop" src="https://kentcdodds.com/static/127992efad005a7454c557a8815c4162/a296c/0.jpg" srcSet="https://kentcdodds.com/static/127992efad005a7454c557a8815c4162/d2274/0.jpg 259w,https://kentcdodds.com/static/127992efad005a7454c557a8815c4162/34151/0.jpg 518w,https://kentcdodds.com/static/127992efad005a7454c557a8815c4162/a296c/0.jpg 800w" sizes="(max-width: 800px) 100vw, 800px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;I recently published a blog post called
&lt;a href="https://kentcdodds.com/blog/why-and-how-i-started-public-speaking"&gt;Why and How I started public speaking&lt;/a&gt;.
I&amp;#x27;m just going to link you to that story rather than re-iterate the whole thing
here. But I do want to tell how I got started with creating content for
&lt;a href="http://egghead.io"&gt;egghead.io&lt;/a&gt; as that made a big influence on widening my
reach.&lt;/p&gt;&lt;p&gt;Back in June 2014, I spoke at
&lt;a href="https://www.meetup.com/AngularJS-Utah/events/173788512"&gt;AngularJS Utah meetup&lt;/a&gt;
about something I had been learning about in a school project
(&lt;a href="https://youtu.be/vIGZxeQUUFU?t=1m51s"&gt;you can watch the talk here!&lt;/a&gt;). Not long
later, &lt;a href="https://twitter.com/johnlindquist"&gt;John Lindquist&lt;/a&gt; (co-founder and
original instructor on &lt;a href="http://egghead.io"&gt;egghead.io&lt;/a&gt;) watched the recording
and emailed me inviting me to turn the workshop into a course.&lt;/p&gt;&lt;p&gt;This lead into an incredible positive relationship. Being an instructor on a
platform like &lt;a href="http://egghead.io"&gt;egghead.io&lt;/a&gt; gives you automatic authority in
the minds of many people. It did take some time and consistency with creating
content on &lt;a href="http://egghead.io"&gt;egghead.io&lt;/a&gt;, but after some time, the following
started to grow (as did my royalties which have been sufficient enough to pay my
monthly home mortgage here in Utah for a couple years now).&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Here&amp;#x27;s the takeaway:&lt;/strong&gt; If my talk had not been recorded, John would not have
seen the value I created that night at the meetup and I could have missed or
delayed my &lt;a href="http://egghead.io"&gt;egghead.io&lt;/a&gt; opportunity. You are constantly
creating value. A conversation with a co-worker, a meetup talk, a realization
after hours of working on a hard to solve bug. &lt;strong&gt;The trick is to take those
value creating experiences and make them public.&lt;/strong&gt;This is where my
&lt;a href="http://kcd.im/devtips"&gt;DevTips with Kent&lt;/a&gt; and my
&lt;a href="http://kcd.im/tech-chats"&gt;Tech Chats&lt;/a&gt; come from. Both of those activities widen
my reach.&lt;/p&gt;&lt;p&gt;Just over a year after I started with &lt;a href="http://egghead.io"&gt;egghead.io&lt;/a&gt; (in
September 2015), after I had established myself a bit with egghead, I was
listening to episode 178 of &lt;a href="https://devchat.tv/js-jabber"&gt;JavaScript Jabber&lt;/a&gt;:
&lt;a href="https://devchat.tv/js-jabber/178-jsj-tech-education-and-the-business-of-running-front-end-masters-with-marc-grabanski"&gt;Tech Education and The Business of Running Front End Masters with Marc Grabanski&lt;/a&gt;.
I had met Marc at my first MidwestJS where we were both speakers and thought he
was a pretty cool dude. I knew of Frontend Masters and had a great deal of
respect for Marc and his company. So I reached out to him:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Hey dude,&lt;br/&gt;I&amp;#x27;m listening to your JSJabber episode and I&amp;#x27;ve been wanting to do a FEM
workshop for a long time. I&amp;#x27;ve been trying to think about what I could
contribute and something that I&amp;#x27;m really into is open source. I have a growing
list of open source libraries&lt;/em&gt; &lt;a href="https://www.npmjs.com/~kentcdodds"&gt;&lt;em&gt;on npm&lt;/em&gt;&lt;/a&gt; &amp;gt;
&lt;em&gt;and&lt;/em&gt; &lt;a href="https://github.com/kentcdodds"&gt;&lt;em&gt;GitHub&lt;/em&gt;&lt;/a&gt; &lt;em&gt;and I&amp;#x27;m the owner and
maintainer of&lt;/em&gt; &amp;gt;
&lt;a href="https://github.com/formly-js/angular-formly"&gt;&lt;em&gt;angular-formly&lt;/em&gt;&lt;/a&gt; &amp;gt; &lt;em&gt;which has
grown in popularity.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;I also have an&lt;/em&gt; &amp;gt;
&lt;a href="https://egghead.io/series/how-to-write-an-open-source-javascript-library"&gt;&lt;em&gt;egghead.io series&lt;/em&gt;&lt;/a&gt; &amp;gt;
&lt;em&gt;on the subject. But, as you know, a workshop format would make it pretty
useful.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;I think that we could get more people into open source if they just knew how
to get started. I believe you&amp;#x27;re interested in open source as well with your
jQuery UI Datepicker experience. I think you could be pretty jazzed about this
workshop.&lt;br/&gt;What do I need to do to make this happen?&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;Thanks!&lt;br/&gt;Kent&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;To which Marc responded:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Sounds awesome! When were you thinking?&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;And so began my relationship with Frontend Masters. I now have
&lt;a href="https://frontendmasters.com/teachers/kentcdodds"&gt;six courses (almost 7) on Frontend Masters&lt;/a&gt;.
&lt;strong&gt;The takeaway here&lt;/strong&gt; is courage. I&amp;#x27;m mostly sharing my success stories in this
blog post, but you gotta know that there were plenty of rejections as well. But
it&amp;#x27;s ok! Have the courage to ask.&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:500px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/66677db6a8e7d983187b70ee297223b6/48a11/1.jpg" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:57.00000000000001%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="You miss 100% of the shots you don&amp;#x27;t take -Wayne Gretzky — Michael Scott" title="You miss 100% of the shots you don&amp;#x27;t take -Wayne Gretzky — Michael Scott" src="https://kentcdodds.com/static/66677db6a8e7d983187b70ee297223b6/48a11/1.jpg" srcSet="https://kentcdodds.com/static/66677db6a8e7d983187b70ee297223b6/d2274/1.jpg 259w,https://kentcdodds.com/static/66677db6a8e7d983187b70ee297223b6/48a11/1.jpg 500w" sizes="(max-width: 500px) 100vw, 500px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;h3&gt;Podcasting&lt;/h3&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:800px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/78c3788a695e59db293a3d933669c038/a296c/2.jpg" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:66.625%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="Microphone" title="Microphone" src="https://kentcdodds.com/static/78c3788a695e59db293a3d933669c038/a296c/2.jpg" srcSet="https://kentcdodds.com/static/78c3788a695e59db293a3d933669c038/d2274/2.jpg 259w,https://kentcdodds.com/static/78c3788a695e59db293a3d933669c038/34151/2.jpg 518w,https://kentcdodds.com/static/78c3788a695e59db293a3d933669c038/a296c/2.jpg 800w" sizes="(max-width: 800px) 100vw, 800px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;I have to mention my podcasts as a form of widening my reach and getting
noticed. Back in November 2014, Todd Motto and I kicked off our bi-weekly Google
Hangouts on Air called &lt;a href="https://angularair.com"&gt;&amp;quot;Angular Air&amp;quot;&lt;/a&gt; with
&lt;a href="https://youtu.be/LG9VkCDbte0"&gt;&amp;quot;Angular Air Episode 0: The Angular Team on 1.3 &amp;amp; 2.0&amp;quot;&lt;/a&gt;.
We didn&amp;#x27;t plan on making it a podcast. We just wanted to chat every other week
between ourselves and maybe a guest or two about AngularJS. We figured it&amp;#x27;d be a
good way to talk to cool people and help the community.&lt;/p&gt;&lt;p&gt;This first episode was so well received that I quickly took the audio from the
YouTube video and created &lt;a href="http://audio.angularair.com"&gt;a podcast&lt;/a&gt; which quickly
started getting thousands of downloads per week. Todd was pretty busy, and I
wanted to go weekly, so I took it over and started getting more and more guests.&lt;/p&gt;&lt;p&gt;What I quickly discovered is that you can get really cool people to freely give
you an hour of their time when you can promise that the value they&amp;#x27;re creating
by talking with you will have an increased impact on thousands of developers all
over the world.&lt;/p&gt;&lt;p&gt;When I made the transition from AngularJS to React at PayPal, I handed off
Angular Air to &lt;a href="https://twitter.com/jeffwhelpley"&gt;Jeff Whelpley&lt;/a&gt; and started
&lt;a href="https://javascriptair.com"&gt;JavaScript Air&lt;/a&gt; with a panel of developers that&amp;#x27;d
knock your socks off and
&lt;a href="https://javascriptair.com/episodes/2015-12-09"&gt;a first episode&lt;/a&gt; with the
creator of JavaScript himself, &lt;a href="https://twitter.com/brendaneich"&gt;Brendan Eich&lt;/a&gt;.
I was able to get these folks because they&amp;#x27;re just awesome people and I had
proven myself to them with my experience as a podcaster with Angular Air and I
could promise them that their time investment would have a great positive impact
on the thousands of developers who would listen to the show. And when you are
able to associate yourself with people like this, their followers will notice
you as well and many become your followers. &lt;strong&gt;I think that of all things, my
podcasts had the biggest impact on my reach while I was running them.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;The show did prove to take more time than I had, so I did eventually
&lt;a href="https://kentcdodds.com/blog/sunsetting-javascript-air"&gt;Sunset JavaScript Air&lt;/a&gt;. But maybe one day I&amp;#x27;ll
start it back up again. It was awesome.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;I&amp;#x27;ll just add here really quick that I&amp;#x27;m also way more likely to be able to
give you an hour of my time if I know that the value we create will be spread
to impact more people. I&amp;#x27;m always happy to join you on a podcast.&lt;/em&gt; &amp;gt;
&lt;a href="https://kentcdodds.com/appearances"&gt;&lt;em&gt;Here&amp;#x27;s a list of podcasts I&amp;#x27;ve been a guest on in the past&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;h3&gt;&lt;a href="http://kcd.im/news"&gt;Newslettering&lt;/a&gt; &amp;amp; &lt;a href="https://kentcdodds.com/blog"&gt;Blogging&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:800px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/cf7cb5246dbabe7cd69c1b78b36628c0/a296c/3.jpg" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:66.625%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="A notebook and a pen" title="A notebook and a pen" src="https://kentcdodds.com/static/cf7cb5246dbabe7cd69c1b78b36628c0/a296c/3.jpg" srcSet="https://kentcdodds.com/static/cf7cb5246dbabe7cd69c1b78b36628c0/d2274/3.jpg 259w,https://kentcdodds.com/static/cf7cb5246dbabe7cd69c1b78b36628c0/34151/3.jpg 518w,https://kentcdodds.com/static/cf7cb5246dbabe7cd69c1b78b36628c0/a296c/3.jpg 800w" sizes="(max-width: 800px) 100vw, 800px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;This newsletter email is being sent as the last email to complete a full year of
weekly newsletters! Without fail, I&amp;#x27;ve sent out an email every week for an
entire year! Two weeks after I send you this newsletter, I publish it to my blog
where it gets several hundred or thousand more views/reads. That amounts to over
50 value-adding blog posts! I&amp;#x27;m pretty amazed that I&amp;#x27;ve been able to keep it up
and I have no plans to stop.&lt;/p&gt;&lt;p&gt;At this moment I have over 7,000 subscribers to my newsletter. But I didn&amp;#x27;t
start with that. Granted, when I started my newsletter I already had a pretty
strong twitter following, but it&amp;#x27;s consistency which has gotten me the
subscribers I have. I still have &amp;gt;50% open rate (which I&amp;#x27;m told is very good).
You subscribers have arrived and stayed at this weekly newsletter because of the
value that I am creating and delivering to your inbox consistently every week.
Hopefully some of you were slightly disappointed when this particular issue came
12 hours later than normal 😅&lt;/p&gt;&lt;p&gt;I&amp;#x27;ve learned that consistency is important with a blog. With the exception of
this newsletter (which has taken many many hours), my newsletters take about an
hour of my time to produce. I can write these during my work hours because
several of you subscribers are PayPal employees and my boss thinks it&amp;#x27;s cool
that I&amp;#x27;m helping educate PayPal every week as well as the community at large.&lt;/p&gt;&lt;h3&gt;&lt;a href="https://twitter.com/kentcdodds"&gt;Tweeting&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:800px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/6470e68478425e3554fc456076a81346/a296c/4.jpg" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:71.375%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="blue bird" title="blue bird" src="https://kentcdodds.com/static/6470e68478425e3554fc456076a81346/a296c/4.jpg" srcSet="https://kentcdodds.com/static/6470e68478425e3554fc456076a81346/d2274/4.jpg 259w,https://kentcdodds.com/static/6470e68478425e3554fc456076a81346/34151/4.jpg 518w,https://kentcdodds.com/static/6470e68478425e3554fc456076a81346/a296c/4.jpg 800w" sizes="(max-width: 800px) 100vw, 800px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Most of my reach is found on twitter. Twitter is a funny and unique place that
we all love to hate (and most of us secretly love). I&amp;#x27;ve found the best way to
be effective on twitter is by following people who (re)tweet
valuable/interesting/relevant stuff, and by (re)tweeting stuff I find
valuable/interesting/relevant. I have no shame in retweeting or promoting
something that&amp;#x27;s valuable even if it also happens to be promoting myself or if
the tweeter says something nice about me. I use twitter as a platform to share
ideas, ask questions, and promote things that I think are important/people will
find useful.&lt;/p&gt;&lt;p&gt;As you might imagine, I have dozens (hundreds?) of DMs sitting in my twitter DM
requests that I&amp;#x27;ve never found the time to respond to. If you&amp;#x27;re sitting in
there waiting I&amp;#x27;m so sorry. Finding time to respond to every DM is impossible,
which leads me to my next point...&lt;/p&gt;&lt;h3&gt;&lt;a href="https://github.com/kentcdodds/ama"&gt;Ask Me Anything&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:800px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/1b139687e84f925c5b96805080d56970/a296c/5.jpg" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:50.625%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="mountain" title="mountain" src="https://kentcdodds.com/static/1b139687e84f925c5b96805080d56970/a296c/5.jpg" srcSet="https://kentcdodds.com/static/1b139687e84f925c5b96805080d56970/d2274/5.jpg 259w,https://kentcdodds.com/static/1b139687e84f925c5b96805080d56970/34151/5.jpg 518w,https://kentcdodds.com/static/1b139687e84f925c5b96805080d56970/a296c/5.jpg 800w" sizes="(max-width: 800px) 100vw, 800px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;In July 2015, I noticed &lt;a href="https://twitter.com/sindresorhus"&gt;Sindre Sorhus&lt;/a&gt;
created a new repo called &lt;a href="https://github.com/sindresorhus/ama"&gt;ama&lt;/a&gt;. It&amp;#x27;s
basically a GitHub repo where people can ask him anything that they like to (he
doesn&amp;#x27;t make any guarantees that he&amp;#x27;ll answer anything though). I thought this
was a great solution to a problem I was beginning to have: Answering the same
questions repeatedly.&lt;/p&gt;&lt;p&gt;So the next day I forked his repo and started my own. I now have over 450
questions answered and regularly direct people there to get their questions
answered or ask new questions. This is another way that I&amp;#x27;m able to increase the
impact of the value that I create. By making my answers public, searchable, and
referenceable, I&amp;#x27;m able to answer way more questions than I could otherwise
&lt;a href="http://kcd.im/no-time"&gt;have time for&lt;/a&gt; and help way more people as well. I do
still have a little trouble answering everything very quickly, but I generally
do get to everything eventually in one form or another.&lt;/p&gt;&lt;h3&gt;The Unquestionable Influence of Privilege&lt;/h3&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:800px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/1be352ff7cc4d5b83f871ae957650ced/a296c/6.jpg" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:66.625%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="a heart on grass" title="a heart on grass" src="https://kentcdodds.com/static/1be352ff7cc4d5b83f871ae957650ced/a296c/6.jpg" srcSet="https://kentcdodds.com/static/1be352ff7cc4d5b83f871ae957650ced/d2274/6.jpg 259w,https://kentcdodds.com/static/1be352ff7cc4d5b83f871ae957650ced/34151/6.jpg 518w,https://kentcdodds.com/static/1be352ff7cc4d5b83f871ae957650ced/a296c/6.jpg 800w" sizes="(max-width: 800px) 100vw, 800px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;We all need to acknowledge something very important: Privilege. If you&amp;#x27;ve not
heard Kyle Simpson talk about
&lt;a href="https://twitter.com/search?q=%23privilegeawareness&amp;amp;src=typd"&gt;#PrivilegeAwareness&lt;/a&gt;,
give the first part of &lt;a href="https://youtu.be/wJEX2FgNYLg?t=46s"&gt;this talk&lt;/a&gt; a quick
watch. I have similar privileges that Kyle mentions. Incidentally, a few hours
after Kyle gave his talk,
&lt;a href="https://youtu.be/-qPh6I2hfjw?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf&amp;amp;t=2m33s"&gt;I gave a talk&lt;/a&gt;
at the same conference where I talk about my privilege as an important thing to
acknowledge.&lt;/p&gt;&lt;p&gt;Yes, I worked really hard to get noticed and gain the reach that I have. But I
would be remiss to not acknowledge the fact that while I was working so hard, I
didn&amp;#x27;t also have to work against prejudices due to the color of my skin or
gender. I grew up with access to technology and a safe and well-off family that
gave me opportunities to excel and succeed.&lt;/p&gt;&lt;p&gt;I think it&amp;#x27;s also important for each of us to be aware of our privilege so we
can work on solving societal problems and actively battle (un)conscious bias as
well as have empathy for those who are in less privileged positions than
ourselves. To &lt;a href="https://youtu.be/8Nvg-MMtN_A"&gt;&amp;quot;lend our privilege&amp;quot;&lt;/a&gt; (that&amp;#x27;s a
link to a fantastic talk by &lt;a href="https://twitter.com/anjuan"&gt;Anjuan Simmons&lt;/a&gt; which
you should watch right now) in an effort to make the world a better place.&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;I sincerely hope this was helpful. I wasn&amp;#x27;t born with a wide reach. And I
haven&amp;#x27;t resented the reach that I have as I have been developing it. I&amp;#x27;ve worked
hard to produce useful content for people who in turn follow me because they
want more of that value which we all create and I capture and disseminate. You
can do this too. Don&amp;#x27;t despair. Keep working at it. Be happy with where you are
and the direction you&amp;#x27;re going. You can do it! Good luck!&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Learn more about career development from me&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://youtu.be/-qPh6I2hfjw?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;Zero to 60 in Software Development: How to Jumpstart Your Career — Forward 4 Web Summit&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://youtu.be/z4DNlVlOfjU?list=PLV5CVI1eNcJi8sor_aQ2AzOeQ3On3suOr"&gt;Testing React with Kent C. Dodds and Jack Franklin&lt;/a&gt; — A
&lt;a href="https://github.com/kentcdodds/ama/issues/125"&gt;tech chat&lt;/a&gt; with myself and
&lt;a href="https://twitter.com/jack_franklin"&gt;Jack Franklin&lt;/a&gt; talking about testing
React. We cover a lot of subjects that you may find interesting!&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/facebook/react/issues/13525"&gt;React Fire 🔥🔥🔥&lt;/a&gt; — An
initiative to modernize react-dom&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.netlify.com/blog/2018/08/29/using-the-react-devtools-profiler-to-diagnose-react-app-performance-issues"&gt;Using the React DevTools Profiler to Diagnose React App Performance Issues&lt;/a&gt;-
A great blog post by &lt;a href="https://twitter.com/swyx"&gt;Shawn Wang&lt;/a&gt; about an awesome
new feature in the React DevTools!&lt;/li&gt;&lt;li&gt;&lt;a href="https://ui.reach.tech"&gt;ui.reach.tech&lt;/a&gt; — An awesome collection of highly
accessible React components by my friend
&lt;a href="https://twitter.com/ryanflorence"&gt;Ryan Florence&lt;/a&gt; (he&amp;#x27;s also giving
&lt;a href="https://reach.tech/workshops"&gt;Advanced React trainings&lt;/a&gt; all over the US
starting in October).&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/getting-noticed-and-widening-your-reach"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Make Impossible States Impossible]]></title>
<description><![CDATA[This is a phrase I first heard from
David Khourshid in his talk at React Rally
2017 Infinitely Better UIs with Finite Automata :
"Make impossible states impossible" (super great talk by the way, and
xstate is awesome, and David is too).
Googling…]]></description>
<link>https://kentcdodds.com/blog/make-impossible-states-impossible</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/make-impossible-states-impossible</guid>
<pubDate>Mon, 10 Sep 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;This is a phrase I first heard from
&lt;a href="https://twitter.com/DavidKPiano"&gt;David Khourshid&lt;/a&gt; in his talk at React Rally
2017 &lt;a href="https://youtu.be/VU1NKX6Qkxc"&gt;Infinitely Better UIs with Finite Automata&lt;/a&gt;:
&amp;quot;Make impossible states impossible&amp;quot; (super great talk by the way, and
&lt;a href="https://github.com/davidkpiano/xstate"&gt;xstate&lt;/a&gt; is awesome, and David is too).
Googling around it looks like it&amp;#x27;s a pretty popular phrase in the
&lt;a href="http://elm-lang.org"&gt;Elm&lt;/a&gt; community, though I&amp;#x27;m not sure who said it first.&lt;/p&gt;&lt;p&gt;To illustrate what this means, let&amp;#x27;s checkout at
&lt;a href="https://codesandbox.io/s/j71ljpvvww"&gt;a very simple example&lt;/a&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;&amp;lt;Alert&amp;gt;Just FYI&amp;lt;/Alert&amp;gt;
&amp;lt;Alert success&amp;gt;It worked!&amp;lt;/Alert&amp;gt;
&amp;lt;Alert warning&amp;gt;Head&amp;#x27;s up&amp;lt;/Alert&amp;gt;
&amp;lt;Alert danger&amp;gt;Watch out!&amp;lt;/Alert&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:652px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/d6d585ac8b7bcfc4b83fb18738e8c504/c2dea/0.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:88.34355828220859%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="Rendered example" title="Rendered example" src="https://kentcdodds.com/static/d6d585ac8b7bcfc4b83fb18738e8c504/c2dea/0.png" srcSet="https://kentcdodds.com/static/d6d585ac8b7bcfc4b83fb18738e8c504/f4a45/0.png 259w,https://kentcdodds.com/static/d6d585ac8b7bcfc4b83fb18738e8c504/ef0f6/0.png 518w,https://kentcdodds.com/static/d6d585ac8b7bcfc4b83fb18738e8c504/c2dea/0.png 652w" sizes="(max-width: 652px) 100vw, 652px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;You may have used or written a component that has this kind of API. It&amp;#x27;s nice
and clean (in case you&amp;#x27;re unfamiliar, in JSX, a non-assigned prop like that is
the same as assigning it to the value &amp;quot;true&amp;quot;, so &lt;code&gt;success&lt;/code&gt; is the same as
&lt;code&gt;success={true}&lt;/code&gt;).&lt;/p&gt;&lt;p&gt;Here&amp;#x27;s where this kind of API falls over. What should I render with this?&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;&amp;lt;Alert success warning&amp;gt;
It worked!
&amp;lt;/Alert&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Should it blend the colors? Should I choose one? Which do I choose? Or should we
just yell at the developer trying to do this because they obviously don&amp;#x27;t know
what they&amp;#x27;re doing? (tip: that last one is &lt;em&gt;NOT&lt;/em&gt; what you should do).&lt;/p&gt;&lt;p&gt;The idea of making impossible states impossible basically means that situations
and questions like these should never come up. It means that you design APIs
that make a clear distinction between the possible states of a component. This
makes the component easier to maintain and to use.&lt;/p&gt;&lt;p&gt;So what do we do with our simple example? Whelp, all these different props
represent is the &lt;em&gt;type&lt;/em&gt; of alert that should be rendered. So what if instead of
simply accepting the prop itself, we accept a &lt;code&gt;type&lt;/code&gt; prop?&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;&amp;lt;AlertBetter&amp;gt;Just FYI&amp;lt;/AlertBetter&amp;gt;
&amp;lt;AlertBetter type=&amp;quot;success&amp;quot;&amp;gt;It worked!&amp;lt;/AlertBetter&amp;gt;
&amp;lt;AlertBetter type=&amp;quot;warning&amp;quot;&amp;gt;Head&amp;#x27;s up&amp;lt;/AlertBetter&amp;gt;
&amp;lt;AlertBetter type=&amp;quot;danger&amp;quot;&amp;gt;Watch out!&amp;lt;/AlertBetter&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now it&amp;#x27;s impossible to have more states than one because there are only three
valid values for the &lt;code&gt;type&lt;/code&gt; prop (well, four if you count &lt;code&gt;undefined&lt;/code&gt;)! It&amp;#x27;s
easier to maintain, easier to explain/understand, and harder to mess up.
Everyone wins!&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;There are various ways to do this effectively and converting a boolean value to
&lt;a href="https://en.wikipedia.org/wiki/Enumerated_type"&gt;an enum&lt;/a&gt; is only one such
mechanism. It can and does get more complicated, but the concept can seriously
simplify your component&amp;#x27;s and application&amp;#x27;s state. This is why I recommend you
give &lt;a href="https://twitter.com/DavidKPiano"&gt;David&amp;#x27;s&lt;/a&gt; talk a watch
(&lt;a href="https://youtu.be/VU1NKX6Qkxc"&gt;here it is again&lt;/a&gt;). And give
&lt;a href="https://github.com/davidkpiano/xstate"&gt;xstate&lt;/a&gt; a solid look as well. There&amp;#x27;s
some good ideas in that! Good luck!&lt;/p&gt;&lt;p&gt;P.S. After publishing this, several people noted that this phrase was the title
of &lt;a href="https://youtu.be/IcgmSRJHu_8"&gt;a talk&lt;/a&gt; from
&lt;a href="https://twitter.com/rtfeldman"&gt;Richard Feldman&lt;/a&gt; at Elm Conf. There&amp;#x27;s also
&lt;a href="https://youtu.be/P7dTPoxCg4w"&gt;a talk&lt;/a&gt; by
&lt;a href="https://twitter.com/ryyppy"&gt;Patrick Stapfer&lt;/a&gt; from ReasonML Munich Meetup. You
may also be interested to check out
&lt;a href="https://github.com/stereobooster/pragmatic-types/blob/master/posts/making-impossible-states-impossible.md"&gt;a similar blog post&lt;/a&gt;
by &lt;a href="https://twitter.com/stereobooster"&gt;@stereobooster&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;P.S.P.S. Further revelation about the origin of a similar phrase:&lt;/p&gt;&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;I did coin the term &amp;quot;make illegal states unrepresentable&amp;quot;, but the idea is of course much older. The phrase &amp;quot;Minsky compliant&amp;quot; surely gives me too much credit, but at least it sounds more positive than the concept of the &amp;quot;Minsky moment&amp;quot;.&lt;/p&gt;— Yaron Minsky (@yminsky) &lt;a href="https://twitter.com/yminsky/status/1034947939364425731"&gt;August 29, 2018&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Learn more about React from me&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://kcd.im/beginner-react"&gt;The Beginner&amp;#x27;s Guide to React&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://kcd.im/advanced-react"&gt;Advanced React Component Patterns&lt;/a&gt; (also on
&lt;a href="https://frontendmasters.com/courses/advanced-react-patterns"&gt;Frontend Masters&lt;/a&gt;).&lt;/li&gt;&lt;li&gt;&lt;a href="https://egghead.io/lessons/react-confidently-ship-production-react-apps"&gt;Confidently Ship Production React Apps&lt;/a&gt; — &lt;strong&gt;A
30 talk on egghead&lt;/strong&gt; (30 minutes... weird right?!) about testing React
components.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://babeljs.io/blog/2018/08/27/7.0.0"&gt;Babel 7 Released&lt;/a&gt; — Congratulations
to the Babel team for releasing Babel 7! I wrote the portion on
&lt;code&gt;babel-plugin-macros&lt;/code&gt;!&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtube.com/watch?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf&amp;amp;v=AiJ8tRRH0f8"&gt;Simply React&lt;/a&gt;:
In my ReactRally talk ⚛️I tell a familiar story about an component that you
can probably relate to. Then I explain how it could have gone better. I think
you&amp;#x27;ll enjoy this!&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/fastpack/fastpack"&gt;&lt;code&gt;fastpack&lt;/code&gt;&lt;/a&gt; - a JavaScript bundler
(like webpack, but with fewer features at the moment) that is BLAZING FAST
🔥🔥🔥🔥 (bundles 1000 modules in &amp;lt; 1 second!)&lt;/li&gt;&lt;li&gt;&lt;a href="https://byteconf.com"&gt;Byteconf React&lt;/a&gt; — Byteconf React is a 100% free
conference with the best JavaScript and React speakers in the world.
Conferences are great, but flights, hotels, and tickets are expensive, so not
everyone can go. Byteconf is streamed on Twitch, for free, so anyone and
everyone can attend. We&amp;#x27;re building a community of developers around the
world — see you there?&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Bonus:&lt;/h3&gt;&lt;p&gt;Here&amp;#x27;s a part from my section in the babel 7 blog post that didn&amp;#x27;t make the
final cut but I thought you&amp;#x27;d enjoy:&lt;/p&gt;&lt;p&gt;Here&amp;#x27;s a very simple example of a custom macro that swaps &lt;code&gt;line&lt;/code&gt;and &lt;code&gt;column&lt;/code&gt;
imports with the line or column where it appears in the code:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;// line-column.macro
module.exports = createMacro(lineColumnMacro)
function lineColumnMacro({references, babel}) {
references.line.forEach(referencePath =&amp;gt; {
const num = referencePath.node.loc.start.line
referencePath.replaceWith(babel.types.numberLiteral(num))
})
references.column.forEach(referencePath =&amp;gt; {
const num = referencePath.node.loc.start.column
referencePath.replaceWith(babel.types.numberLiteral(num))
})
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And then this code:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;`import {line, column} from &amp;#x27;./line-column.macro&amp;#x27;
`
``console.log(`we&amp;#x27;re at ${line}:${column}`)
console.log(`and now we&amp;#x27;re at ${line}:${column}`)``
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will be transpiled into:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;console.log(`we&amp;#x27;re at ${3}:${32}`)
console.log(`and now we&amp;#x27;re at ${4}:${40}`)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And we don&amp;#x27;t need to change any config to add that custom transform. Writing and
using code transforms is a fair amount easier this way. You can&amp;#x27;t do everything
that a full babel plugin can do, but we&amp;#x27;re only just getting started with this
and look forward to what the community will do with this power.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Play around with the above macro example&lt;/em&gt; &amp;gt;
&lt;a href="https://astexplorer.net/#/gist/e586bcbbf2ce35835115a7d808528c90/b64f5f025d98481ebfb93a582334c8562f7337f0"&gt;&lt;em&gt;on astexplorer.net&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.
See if you can make it support an import called&lt;/em&gt; &lt;code&gt;_lineColumn_&lt;/code&gt;&lt;em&gt;that is
replaced with the sum of line and column. Just for fun!&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/make-impossible-states-impossible"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[How to make the most out of conferences]]></title>
<description><![CDATA[I spent the last week at React Rally in Salt Lake
City. It was an awesome experience. It's easily my favorite conference. I've
been to at least two dozen unique conferences. Here are some of the reasons
React Rally is my favorite: Tons of time to…]]></description>
<link>https://kentcdodds.com/blog/how-to-make-the-most-out-of-conferences</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/how-to-make-the-most-out-of-conferences</guid>
<pubDate>Mon, 03 Sep 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;I spent the last week at &lt;a href="https://www.reactrally.com"&gt;React Rally&lt;/a&gt; in Salt Lake
City. It was an awesome experience. It&amp;#x27;s easily my favorite conference. I&amp;#x27;ve
been to at least two dozen unique conferences. Here are some of the reasons
React Rally is my favorite:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Tons of time to meet other people&lt;/li&gt;&lt;li&gt;The community Rocks&lt;/li&gt;&lt;li&gt;Focus on meeting people and interaction&lt;/li&gt;&lt;li&gt;Single track&lt;/li&gt;&lt;li&gt;Less than 750 attendees (~550 I think)&lt;/li&gt;&lt;li&gt;Lunch is &amp;quot;on your own&amp;quot; (they give you a gift-card and you pick the local
restaurants)&lt;/li&gt;&lt;li&gt;Less alcohol (none provided in this case), more board games, yummy desserts,
and karaoke&lt;/li&gt;&lt;li&gt;Top-notch speakers, new speakers, and diverse people and topics (as diverse of
topics as you can get within the React ecosystem)&lt;/li&gt;&lt;li&gt;Organizers are just super people&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Things that could have made it better:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Improved diversity in attendees. It&amp;#x27;s better than some conferences, but not as
diverse as others&lt;/li&gt;&lt;li&gt;The hotel venue is a pretty convenient location, but hotels in general are a
little dull&lt;/li&gt;&lt;li&gt;Put twitter/github avatars on attendee&amp;#x27;s badges. It will allow connections to
happen much more easily!&lt;/li&gt;&lt;li&gt;Pre-conference party would be great. Strange Loop has a very unique and
amazing pre-conference party/venue. It allowed me to meet a bunch of people I
was able to greet throughout the rest of the conference.&lt;/li&gt;&lt;li&gt;Speaking toward the end of the conference makes the whole experience
sub-optimal. But someone&amp;#x27;s gotta do it so I was happy to take one for the team
😅&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;So there&amp;#x27;s a little feedback from my perspective for the organizers and people
evaluating the conference. Now, let me turn my attention to what I believe you
can do to get the most out of your conference experience.&lt;/p&gt;&lt;h3&gt;Pay attention to the talks&lt;/h3&gt;&lt;p&gt;This seems pretty obvious, but I definitely fall into this trap myself on
occasion. Sometimes you can&amp;#x27;t get away from work, but if you&amp;#x27;re scrolling
through Twitter during a talk, you&amp;#x27;re missing out on the learning you could be
experiencing. Sure, you can watch the talk later, but can you watch it before
you meet the speaker in the hallway when it&amp;#x27;d be the perfect time to ask them
the question you&amp;#x27;ll have when you &lt;em&gt;actually&lt;/em&gt; experience the talk?&lt;/p&gt;&lt;p&gt;Pay attention to the talks, and you&amp;#x27;ll have common ground with anyone with whom
you&amp;#x27;d like to discuss particulars and nuances of the subject, including the
speaker themselves. Should you take notes? That&amp;#x27;s up to you (I don&amp;#x27;t normally
take notes personally). A successful talk requires a speaker and an audience.
&lt;a href="https://education.byu.edu/magazine/winter2016/act_well_thy_part"&gt;What-E&amp;#x27;er Thou Art, Act Well Thy Part.&lt;/a&gt;&lt;/p&gt;&lt;h3&gt;Attend talks you think you already know all about&lt;/h3&gt;&lt;p&gt;You&amp;#x27;ll be surprised what you can learn about the things you assume you already
know very well. Beyond that, if you really do already know the content, watching
someone else present it can help you learn new ways to teach the information,
give you a new perspective you hadn&amp;#x27;t before considered, or potentially show you
a different understanding or a misunderstanding in the community about that
subject. Whatever the case, you will be better having listened and attended.&lt;/p&gt;&lt;h3&gt;Take advantage of the hallway track&lt;/h3&gt;&lt;p&gt;The &amp;quot;hallway track&amp;quot; at a conference is just a term that&amp;#x27;s been given to the
impromptu conversations that naturally strike up during
breaks/lunch/parties/etc. Take advantage of that time. You and many others there
spent a lot of money and time to be there. Look for opportunities to make new
connections and exchange contact info (or Twitter follows).
&lt;a href="https://github.com/kentcdodds/ama/issues/47"&gt;I got my current job at PayPal&lt;/a&gt;
because I met a few people during the breaks at React Rally a few years ago and
connected with them on Twitter. You can also learn a lot. The speakers are not
the only experts attending the conference. Ask people about their work. Leave
room in your circle to be joined by others. Be as inviting as possible. You
never know who might be your new best friend, your next mentee, or your future
co-founder.&lt;/p&gt;&lt;h3&gt;Take breaks; take care of yourself.&lt;/h3&gt;&lt;p&gt;Conferences (especially of the multi-day variety) are exhausting. Drink plenty
of water and eat well to give you the energy that your body and brain need. When
you wake up in the morning, do some stretches (and air squats). And when you&amp;#x27;re
feeling your body protest, &lt;em&gt;listen to your body&lt;/em&gt; and find somewhere to sit,
disengage and disconnect. Meditate, pray, whatever. You&amp;#x27;ll be glad that you took
that time to take care of yourself. This is pretty good advice for daily living
I think :)&lt;/p&gt;&lt;h3&gt;Speak&lt;/h3&gt;&lt;p&gt;This is a subject unto itself (I actually talked about it in last week&amp;#x27;s
newsletter
&lt;a href="https://kentcdodds.com/blog/why-and-how-i-started-public-speaking"&gt;&amp;quot;Why and How I started public speaking&amp;quot;&lt;/a&gt;),
but I would encourage you to get involved in speaking at conferences. This does
add a whole new layer of stress to your experience, but there are a great deal
of benefits as well. I definitely encourage speaking as a way to get to attend
conferences you cannot otherwise afford as well!&lt;/p&gt;&lt;p&gt;When I speak, I often need some time to recharge. Definitely take care of
yourself. Once you&amp;#x27;ve taken care of yourself, remember that other people may
want to talk with you about the content of your talk. Give them a chance to chat
with you. It&amp;#x27;s a lot of fun :)&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;Most conferences make talk recordings available after the conference, so the
focus of my conference going is building relationships and meeting people.
Attending the talks help give you talking points and can introduce you to new
concepts that you may not have thought to watch after the fact anyway. Good luck
making the most of the conferences you&amp;#x27;re able to attend! It&amp;#x27;s truly a privilege
to go.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://github.com/bradlc/tinker.macro"&gt;tinker.macro&lt;/a&gt; by
&lt;a href="https://twitter.com/bradlc"&gt;Brad Cornes&lt;/a&gt; is an amazing PHP in JS macros for
babel-plugin-macros. How cool!?&lt;/li&gt;&lt;li&gt;&lt;a href="https://philipwalton.com/articles/deploying-es2015-code-in-production-today"&gt;Deploying ES2015 code in Production Today&lt;/a&gt; — A
remarkably simple method for deploying ES5 and ES2015 code to browsers based
on whether they support &lt;code&gt;&amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;/code&gt;. See also:
&lt;a href="https://bundle.sh"&gt;bundle.sh&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/johnlindquist/next-mdx-blog"&gt;&lt;code&gt;next-mdx-blog&lt;/code&gt;&lt;/a&gt; - an example
by &lt;a href="https://twitter.com/johnlindquist"&gt;John Lindquist&lt;/a&gt;. Uses
&lt;a href="https://github.com/kentcdodds/babel-plugin-preval"&gt;&lt;code&gt;preval&lt;/code&gt;&lt;/a&gt; to run mdx.
Pretty rad TBH :)&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/how-to-make-the-most-out-of-conferences"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Why and How I started public speaking]]></title>
<description><![CDATA[When I was still in school in the Information Systems program at
BYU , I discovered and started listening to
JavaScript Jabber . At the time,
Jamison Dance was on the show and also the
organizer of the local JavaScript meetup. I remember him…]]></description>
<link>https://kentcdodds.com/blog/why-and-how-i-started-public-speaking</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/why-and-how-i-started-public-speaking</guid>
<pubDate>Mon, 27 Aug 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:800px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/dd302ef952fcbe9a59fdc44bd5459fbf/a296c/0.jpg" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:75%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="Kent C. Dodds in front of an audience at a meetup" title="Kent C. Dodds in front of an audience at a meetup" src="https://kentcdodds.com/static/dd302ef952fcbe9a59fdc44bd5459fbf/a296c/0.jpg" srcSet="https://kentcdodds.com/static/dd302ef952fcbe9a59fdc44bd5459fbf/d2274/0.jpg 259w,https://kentcdodds.com/static/dd302ef952fcbe9a59fdc44bd5459fbf/34151/0.jpg 518w,https://kentcdodds.com/static/dd302ef952fcbe9a59fdc44bd5459fbf/a296c/0.jpg 800w" sizes="(max-width: 800px) 100vw, 800px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;When I was still in school in the Information Systems program at
&lt;a href="https://www.byu.edu"&gt;BYU&lt;/a&gt;, I discovered and started listening to
&lt;a href="https://devchat.tv/js-jabber"&gt;JavaScript Jabber&lt;/a&gt;. At the time,
&lt;a href="https://twitter.com/jergason"&gt;Jamison Dance&lt;/a&gt; was on the show and also the
organizer of the local JavaScript meetup. I remember him mentioning the meetup
on the show and thought it&amp;#x27;d be really cool to attend and learn from others
(which it is!).&lt;/p&gt;&lt;p&gt;So I looked up the
&lt;a href="https://www.meetup.com/UtahJS-Orem-Meetup/events/156148202"&gt;meetup page&lt;/a&gt; he
mentioned and noticed that there was an opening for a speaker. I had just gotten
back from the first ng-conf (2014) and thought that whole public speaking thing
looked like a lot of fun. I also had been working on a personal open source
project on the side called &lt;a href="https://github.com/kentcdodds/genie"&gt;geniejs&lt;/a&gt; (which
was part of how I eventually got
&lt;a href="https://github.com/kentcdodds/ama/issues/1"&gt;my first job&lt;/a&gt;) and thought if they
needed a speaker I could talk about genie! So I offered to fill their slot:&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:800px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/a8df5037617e142c582c15c08fe2a35f/8ff1e/1.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:136.875%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="a comment thread showing a request to speak at a meetup" title="a comment thread showing a request to speak at a meetup" src="https://kentcdodds.com/static/a8df5037617e142c582c15c08fe2a35f/8ff1e/1.png" srcSet="https://kentcdodds.com/static/a8df5037617e142c582c15c08fe2a35f/f4a45/1.png 259w,https://kentcdodds.com/static/a8df5037617e142c582c15c08fe2a35f/ef0f6/1.png 518w,https://kentcdodds.com/static/a8df5037617e142c582c15c08fe2a35f/8ff1e/1.png 800w" sizes="(max-width: 800px) 100vw, 800px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;And just like that, the first meetup I attended I was a speaker. Turns out
meetup organizers are often willing to give a speaking slot to anyone who so
much as sneezes in their direction because speakers are surprisingly hard to
come by on a monthly basis 😅&lt;/p&gt;&lt;p&gt;So there&amp;#x27;s the history of how I got started with public speaking in tech.&lt;/p&gt;&lt;h4&gt;&lt;strong&gt;So why did I do it?&lt;/strong&gt;&lt;/h4&gt;&lt;p&gt;I can think of two reasons:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;I thought my library was cool and really wanted people to start using it.&lt;/li&gt;&lt;li&gt;I thought it would be fun.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I know a lot of people think that public speaking is worse than death. &lt;em&gt;How on
earth could I think it&amp;#x27;s fun?&lt;/em&gt; Well, if you don&amp;#x27;t mind, let me give you a little
context into my childhood...&lt;/p&gt;&lt;p&gt;Ever since I was a little child, I&amp;#x27;ve been speaking in front of groups of
people. As a child, I spoke in &lt;a href="https://www.mormon.org"&gt;my Church&amp;#x27;s&lt;/a&gt; primary
program (in front of a handful of adult instructors and a few dozen of my peers)
a dozen times or so. When I was a teenager, I had a speech class in school,
started giving short talks in
&lt;a href="https://www.mormonnewsroom.org/topic/seminary"&gt;my seminary classes&lt;/a&gt;, and gave 5
minute talks in front of my entire church congregation (a
&lt;a href="https://www.mormonnewsroom.org/article/ward"&gt;&amp;quot;Ward&amp;quot;&lt;/a&gt;consisting of ~200 people).
By the time I moved out of my home at 18, I had probably given 40 talks of
various lengths and on various subjects (though most were religious in nature).
During that time I also gave ~15 minute lessons to my family in
&lt;a href="https://www.lds.org/topics/family-home-evening/purpose"&gt;family home evenings&lt;/a&gt;,
and led lessons in my church classes as well.&lt;/p&gt;&lt;p&gt;In Junior High and High School, I was also a stage performer. I
&lt;a href="https://youtu.be/agdbnzQlMFE"&gt;played the piano&lt;/a&gt; (yes, I&amp;#x27;m hitting my head and
forearm on the piano at ~2 minutes),
&lt;a href="https://youtu.be/F5_QmWwIF3c"&gt;sang in choirs&lt;/a&gt;, and I was in
&lt;a href="https://youtu.be/5_sRK8UUc3k"&gt;my High School&amp;#x27;s Show Choir &amp;quot;Jive!&amp;quot;&lt;/a&gt; (yep, that&amp;#x27;s
me in the green doing a backflip at ~6:40). After leaving home and spending a
semester at BYU, I left on
&lt;a href="https://www.mormonnewsroom.org/topic/missionary-program"&gt;a mission for my church&lt;/a&gt;
and had even more opportunities to speak in front of people (both church
congregations as well as teach lessons to people in their homes).&lt;/p&gt;&lt;h4&gt;&lt;strong&gt;So why did I think it&amp;#x27;d be fun?&lt;/strong&gt;&lt;/h4&gt;&lt;p&gt;I guess it&amp;#x27;s because I was privileged to grow up with opportunities that allowed
the fears surrounding public speaking to fall away and all that&amp;#x27;s left is the
pure joy of sharing experiences and connecting with people in a big way.&lt;/p&gt;&lt;p&gt;I&amp;#x27;m mentioning all of this in part for me to walk down memory lane, but also to
illustrate that growing up, I spent a LOT of time in front of people. This will
hopefully give you more context into the why and how I started speaking publicly
at tech meetups and conferences, and hopefully will give you some ideas of what
you can start doing today if that&amp;#x27;s something you want to do more of as well.&lt;/p&gt;&lt;p&gt;So that&amp;#x27;s why and how I started public speaking. From there it was pretty
natural to transition to speaking at conferences. I wanted to speak at
conferences because, as I said, I&amp;#x27;d just gotten back from my first ever tech
conference (ng-conf) and it was awesome. I wanted to go to more, but my company
wouldn&amp;#x27;t pay for all the conferences I wanted to attend, so I needed to find
some other way to afford going. So my motivation to speak at conferences was
primarily to be able to attend.&lt;/p&gt;&lt;p&gt;Conference speakers normally have all expenses paid (as they should), so I
started searching around for open conference CFPs (Call For Proposals) (I used
&lt;a href="https://twitter.com/lanyrd"&gt;Lanyrd&lt;/a&gt;, but I think
&lt;a href="https://confs.tech"&gt;confs.tech&lt;/a&gt; is probably better these days. I&amp;#x27;m sure there
are more... Google around 😉). I wrote a dozen or so proposals about subjects
that I knew I could write and deliver a fun and informative talk from. I
submitted them to every relevant conference I could. One conference I was
accepted to was Jfokus which is in Stockholm, Sweden (a fact that I realized
only &lt;em&gt;after&lt;/em&gt; I&amp;#x27;d been accepted 😅). They invited me to give a workshop as well
and that&amp;#x27;s how I got my first paid workshop gig. (Another story is the fact that
speaking at a meetup was how I got my gig at &lt;a href="http://egghead.io"&gt;egghead.io&lt;/a&gt; as
well).&lt;/p&gt;&lt;p&gt;I was able to attend a ton of conferences. Too many actually. As awesome as it
was, it started to negatively impact my family and work. So I&amp;#x27;ve pulled back
considerably, and now I have to be a lot more picky about which conferences I&amp;#x27;ll
submit to.&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;So why do I speak at meetups and conferences now?&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The joy of sharing knowledge and connecting with an audience&lt;/li&gt;&lt;li&gt;The ability to travel and see new places&lt;/li&gt;&lt;li&gt;Become a recognized name in the industry to (hopefully) help secure my
family&amp;#x27;s financial stability&lt;/li&gt;&lt;li&gt;Promote the practices and technologies that I enjoy in an effort to increase
the community around them&lt;/li&gt;&lt;li&gt;To &lt;a href="https://kentcdodds.com/blog/solidifying-what-you-learn"&gt;solidify what I&amp;#x27;m learning&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;How did I get into public speaking?&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;I spent a TON of time in front of people.&lt;/strong&gt; Early in childhood, these (large
and small) opportunities came upon me thanks to others in my life. Now I
actively search for these opportunities (both large and small).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;I wasn&amp;#x27;t afraid of rejection.&lt;/strong&gt; Just ask, and keep asking. Early on, I had
about a %5 acceptance rate for my conference proposals (though probably a 95%
acceptance rate for my meetup &amp;quot;proposals&amp;quot; 😅).&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I really hope this is helpful to you. I definitely still get nervous before
speaking, just like I was always nervous before performing in stage or speaking
in church as a kid. That never goes away. But the more practice you get, the
more able you will be to take that nervous energy and turn it into positive
energy to get the audience engaged which will help you connect with them better.
Keep practicing! Good luck :D&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Learn more about &amp;quot;self improvement&amp;quot; from me&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://youtu.be/-qPh6I2hfjw?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;Zero to 60 in Software Development: How to Jumpstart Your Career&lt;/a&gt; — A
talk I gave a few years ago that&amp;#x27;s related and has some similar stories to
this post.&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Folks have been telling me I should make a course about (the good side of)
personal brand marketing / self-promotion. Let me know if you&amp;#x27;d be interested
in this.&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://hackernoon.com/how-and-why-to-speak-at-tech-conferences-1d50a3f548e0"&gt;How and Why to Speak at Tech Conferences&lt;/a&gt;
by &lt;a href="https://twitter.com/nickheiner"&gt;Nick Heiner&lt;/a&gt; — A great blog post that goes
deeper on this subject.&lt;/li&gt;&lt;li&gt;&lt;a href="http://testandcode.com/45"&gt;Test and Code Episode 45: David Heinemeier Hansson — Software Development and Testing, TDD, and exploratory QA&lt;/a&gt;-
A refreshingly practical view of testing software from the creator of Ruby on
Rails.&lt;/li&gt;&lt;li&gt;&lt;a href="http://kcd.im/devtips"&gt;DevTips&lt;/a&gt; — If you&amp;#x27;re not reviewing these on a regular
basis, I suggest you do. I put out some pretty cool things on this playlist.
You could make it easy on yourself and
&lt;a href="http://kcd.im/youtube"&gt;subscribe to my youtube channel&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/why-and-how-i-started-public-speaking"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[mdx-deck: slide decks powered by markdown and react]]></title>
<description><![CDATA[I've been giving presentations for years. I like many others started with
PowerPoint because "that's how you make presentations." I moved on from that to
Prezi when I was in college and I wowed all the crowds. I
moved on from that because it felt…]]></description>
<link>https://kentcdodds.com/blog/mdx-deck-slide-decks-powered-by-markdown-and-react</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/mdx-deck-slide-decks-powered-by-markdown-and-react</guid>
<pubDate>Mon, 20 Aug 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;I&amp;#x27;ve been giving presentations for years. I like many others started with
PowerPoint because &amp;quot;that&amp;#x27;s how you make presentations.&amp;quot; I moved on from that to
&lt;a href="https://prezi.com"&gt;Prezi&lt;/a&gt; when I was in college and I wowed all the crowds. I
moved on from that because it felt too gimmicky for the kinds of presentations I
was making. I tried Google Slides and that was cool because it&amp;#x27;s web-tech, but
was a little limited and didn&amp;#x27;t look all that nice. Eventually I landed at
&lt;a href="https://slides.com"&gt;slides.com&lt;/a&gt;. I&amp;#x27;ve been with slides for pretty much my
entire software development presentation career. You&amp;#x27;ll find pretty much 100% of
the public presentations I&amp;#x27;ve made on
&lt;a href="https://slides.com/kentcdodds"&gt;my slides page&lt;/a&gt; (including
&lt;a href="https://slides.com/kentcdodds/genie"&gt;my first meetup talk&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;I&amp;#x27;ve been pretty happy with slides because it&amp;#x27;s really easy to create
presentations and I&amp;#x27;ve never been one to spend a ton of time on my slides. I
just want to make them quickly and focus on practicing my presentation to
communicate effectively what I want. But it definitely has some shortcomings and
limitations, and there are some things about the WYSIWYG interface that really
bug me. So I&amp;#x27;ve always been on the lookout for a better experience creating
slides. (Now&amp;#x27;s as good a time as any to admit that I&amp;#x27;ve never used Keynote. But
I didn&amp;#x27;t want to pay for it and I don&amp;#x27;t think that I&amp;#x27;d be willing to spend the
time working on the slides to make it any better than slides anyway).&lt;/p&gt;&lt;p&gt;Probably the biggest example of the limitations of slides that really bothers me
is the difficulty of including interactive elements on the page. I always admire
people who&amp;#x27;s slides are made with HTML, CSS, and JS because they can just add
their interactive demos directly to their slides which increases &amp;quot;the wow
factor&amp;quot; in addition to being generally more engaging. For a specific example,
&lt;a href="https://slides.com/kentcdodds/simply-react"&gt;my slides&lt;/a&gt; for my &amp;quot;Simply React&amp;quot;
keynote at ChainReact had several demos that were recorded video which is not
awesome, but I also had an issue where I couldn&amp;#x27;t replay the videos
(&lt;a href="https://youtu.be/M9X2qGddHkU?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf&amp;amp;t=4m04s"&gt;watch here&lt;/a&gt;).
So the demos kinda fell flat a bit.&lt;/p&gt;&lt;p&gt;When master &lt;a href="https://twitter.com/ken_wheeler"&gt;Ken Wheeler&lt;/a&gt; announced
&lt;a href="https://github.com/FormidableLabs/spectacle"&gt;spectacle&lt;/a&gt; I was super excited! It
is so awesome! I never got into it though because I&amp;#x27;m just too lazy and wasn&amp;#x27;t
willing to take the time to make slides out of React code and customize it to
what I want it to be. So though I&amp;#x27;ve tried it a few times, it never really took
off for me.&lt;/p&gt;&lt;h3&gt;Enter MDX&lt;/h3&gt;&lt;p&gt;A few months ago &lt;a href="https://twitter.com/4lpine"&gt;John Otander&lt;/a&gt; released the initial
version of a new tool (and
&lt;a href="https://github.com/mdx-js/specification"&gt;specification&lt;/a&gt;) called
&lt;a href="https://github.com/mdx-js/mdx"&gt;MDX&lt;/a&gt;. Months later
&lt;a href="https://twitter.com/timneutkens"&gt;Tim Neutkens&lt;/a&gt;
&lt;a href="https://youtu.be/yqACl3tRHNI?t=10m"&gt;announced MDX during the Zeit Day 2018 Keynote&lt;/a&gt;
and the world&amp;#x27;s collective minds were blown
(&lt;a href="https://twitter.com/ryanflorence/status/1024522677262794752"&gt;for example&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;Here&amp;#x27;s a quick example of what&amp;#x27;s possible with MDX:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-md"&gt;import InteractiveGraph from &amp;#x27;./my-d3-graph&amp;#x27;
# Checkout this cool graph!
&amp;gt; This is markdown, for real
&amp;lt;InteractiveGraph /&amp;gt;
**That&amp;#x27;s right!** We&amp;#x27;re rendering a **React Component** in Markdown!
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There&amp;#x27;s a bunch that&amp;#x27;s awesome from this. I&amp;#x27;ve been wanting something like this
for quite some time! Back when I was working on the website for
&lt;a href="https://github.com/paypal/glamorous"&gt;glamorous&lt;/a&gt;
(&lt;a href="https://glamorous.rocks"&gt;glamorous.rocks&lt;/a&gt;), I wanted to make all the docs in
markdown to make it easier to internationalize, but I also wanted interactivity
to be possible, so I came up with
&lt;a href="https://github.com/kentcdodds/glamorous-website/blob/master/other/CONTRIBUTING_DOCUMENTATION.md#important-markdown-notes"&gt;a super weird syntax&lt;/a&gt;
to make this possible. It&amp;#x27;s pretty cool, and actually works similar to MDX at a
fundamental level (uses
&lt;a href="https://github.com/kentcdodds/glamorous-website/blob/b2469c1dfbfed750fc01dcbe411fec307b7ae5a8/components/interactive-markdown.js#L89-L113"&gt;a custom fancy plugin&lt;/a&gt;
for &lt;a href="https://github.com/remarkjs/remark"&gt;remark&lt;/a&gt;), but it&amp;#x27;s way hacky and
limited. This MDX thing is the REAL DEAL!&lt;/p&gt;&lt;h3&gt;Enter mdx-deck&lt;/h3&gt;&lt;p&gt;Recently, the (seriously) amazing &lt;a href="https://twitter.com/jxnblk"&gt;Brent Jackson&lt;/a&gt;
created and &lt;a href="https://twitter.com/jxnblk/status/1023667155324346373"&gt;announced&lt;/a&gt;
something absolutely amazing: &lt;a href="https://github.com/jxnblk/mdx-deck"&gt;&lt;strong&gt;mdx-deck&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="https://camo.githubusercontent.com/c12c8d143a3509f9aa6fde5629ea0c7f78e68437/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6a786e626c6b2f6d64782d6465636b2e676966" alt="gif showing mdx-deck demo"/&gt;&lt;/p&gt;&lt;p&gt;It&amp;#x27;s got the ease of slides that I love because it&amp;#x27;s just markdown. Couldn&amp;#x27;t be
much easier than that! Then, to top that off, if I want something to be
interactive, I can simply make that interactive thing a React component, then
import that directly into my slide!! How awesome is that!? Way awesome is the
answer!&lt;/p&gt;&lt;p&gt;mdx-deck has some pretty sweet features too:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;📝 Write presentations in markdown&lt;/li&gt;&lt;li&gt;⚛️ Import and use
&lt;a href="https://github.com/jxnblk/mdx-deck#imports"&gt;React components&lt;/a&gt;&lt;/li&gt;&lt;li&gt;💅 Customizable &lt;a href="https://github.com/jxnblk/mdx-deck#theming"&gt;themes&lt;/a&gt; and
components&lt;/li&gt;&lt;li&gt;0️⃣ Zero-config CLI&lt;/li&gt;&lt;li&gt;💁 &lt;a href="https://github.com/jxnblk/mdx-deck#presenter-mode"&gt;Presenter mode&lt;/a&gt;&lt;/li&gt;&lt;li&gt;📓 &lt;a href="https://github.com/jxnblk/mdx-deck#speaker-notes"&gt;Speaker notes&lt;/a&gt;&lt;/li&gt;&lt;li&gt;📓 &lt;a href="https://github.com/jxnblk/mdx-deck#exporting"&gt;Production Export&lt;/a&gt;&lt;/li&gt;&lt;li&gt;📜 &lt;a href="https://github.com/jxnblk/mdx-deck#pdf-export"&gt;PDF Export&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;You combine this with
&lt;a href="https://www.netlify.com/docs/continuous-deployment"&gt;Netlify&amp;#x27;s amazing GitHub Integration&lt;/a&gt;
and put your slides in a GitHub project and you&amp;#x27;re off to the races with an
automatically deployed slide deck!&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;I&amp;#x27;m currently working on porting my slides for
&lt;a href="https://github.com/kentcdodds/simply-react"&gt;&amp;quot;Simply React&amp;quot;&lt;/a&gt;. You can see the
current state of
&lt;a href="https://simply-react.netlify.com"&gt;the slides deployed on netlify here&lt;/a&gt; (and
&lt;a href="https://simply-react.netlify.com/presentation.pdf"&gt;the pdf&lt;/a&gt;). I&amp;#x27;m pretty jazzed
about the ability to have such an easy way to create presentations in the
browser that are easy to run locally, deployed to the web, create a PDF version,
&lt;em&gt;and&lt;/em&gt; totally interactive. This is just terrific.&lt;/p&gt;&lt;p&gt;Give it a look and try it for your next presentation. I think you&amp;#x27;ll love it.
Good luck!&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/mdx-deck-slide-decks-powered-by-markdown-and-react"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[unpkg: An open source CDN for npm]]></title>
<description><![CDATA[A few years ago, Michael Jackson had an idea. He
needed an easy way to make demos for his open source projects (specifically
react-router ) and realized that he
already hosts all his projects somewhere: npm! So he could just setup a little
node…]]></description>
<link>https://kentcdodds.com/blog/unpkg-an-open-source-cdn-for-npm</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/unpkg-an-open-source-cdn-for-npm</guid>
<pubDate>Mon, 13 Aug 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;A few years ago, &lt;a href="https://twitter.com/mjackson"&gt;Michael Jackson&lt;/a&gt; had an idea. He
needed an easy way to make demos for his open source projects (specifically
&lt;a href="https://reacttraining.com/react-router"&gt;react-router&lt;/a&gt;) and realized that he
already hosts all his projects somewhere: npm! So he could just setup a little
node server that would act as a proxy to the files that are on npm. And here we
are, almost 9 BILLION downloads per month later.&lt;/p&gt;&lt;p&gt;&lt;a href="https://unpkg.com"&gt;unpkg&lt;/a&gt; is an
&lt;a href="https://github.com/unpkg/unpkg.com"&gt;open source&lt;/a&gt; fast, global
&lt;a href="https://en.wikipedia.org/wiki/Content_delivery_network"&gt;content delivery network&lt;/a&gt;
for everything on &lt;a href="https://www.npmjs.com"&gt;npm&lt;/a&gt;. Use it to quickly and easily
load any file from any package using a URL like:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;unpkg.com/:package@:version/:file
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For example, to get d3 on your page, you could add a script tag like so:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;&amp;lt;script src=&amp;quot;https://unpkg.com/d3@5.5.0/dist/d3.min.js&amp;quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You could also do:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;&amp;lt;script src=&amp;quot;https://unpkg.com/d3&amp;quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Because unpkg redirects those to the above URL (in this case it&amp;#x27;s because d3&amp;#x27;s
&lt;code&gt;package.json&lt;/code&gt; has a &lt;code&gt;unpkg&lt;/code&gt; field to point to that file specifically). It&amp;#x27;s
recommended that you specify a version though because otherwise user&amp;#x27;s will
start downloading the latest version which could break your application if
there&amp;#x27;s a major version bump:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;&amp;lt;script src=&amp;quot;https://unpkg.com/d3@^5.5.0&amp;quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That&amp;#x27;s right, a version range works in there as well. Cool right?&lt;/p&gt;&lt;p&gt;So why is this so cool? Whelp, we use CDNs (content delivery networks) because
they allow static assets like images, JavaScript, and videos to be hosted
physically close to end users as well as served with as fast as possible
technology. unpkg is sponsored by &lt;a href="https://www.heroku.com"&gt;Heroku&lt;/a&gt; where it is
hosted, but that server is only actually used 5% of the time. The real power of
a tool like unpkg is the fact that the files hosted at those URLs can be very
heavily cached (npm doesn&amp;#x27;t allow published packages to be changed). So unpkg is
also sponsored by &lt;a href="https://www.cloudflare.com"&gt;Cloudflare&lt;/a&gt; which is an awesome
CDN and serves 95% of unpkg&amp;#x27;s traffic from the cache, making unpkg extremely
fast.&lt;/p&gt;&lt;p&gt;unpkg is great for open source project demos and instructional material (I use
it heavily in my &lt;a href="http://kcd.im/beginner-react"&gt;Beginner&amp;#x27;s Guide to ReactJS&lt;/a&gt;),
but it&amp;#x27;s not well suited for mission-critical applications at scale because:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;unpkg is a free, best-effort service and cannot provide any uptime or support
guarantees.&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;That&amp;#x27;s why Michael recommends:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;if you rely on it to serve files that are crucial to your business, you
should probably pay for a host with well-supported infrastructure and uptime
guarantees.&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;This is something that I plan on doing at PayPal eventually and I&amp;#x27;ll tell you
why. Most projects at PayPal are using much of the same technology. Most are
using some version of react and react-dom, some are using rxjs, many are using
lodash. Each of these projects serves its own &lt;code&gt;bundle.js&lt;/code&gt; file(s) that include
these dependencies. So as users navigate around PayPal they&amp;#x27;re re-downloading
much of the same code just in a different form. Some companies enforce the
entire company use the same version of some dependencies to avoid this problem.
I think this comes with more problems than the solution merits&lt;/p&gt;&lt;p&gt;This is why I&amp;#x27;m really interested in building a hosted version of unpkg at
PayPal. Doing this will allow teams to use whatever version of whatever
dependencies they like. If two teams happen to be using the same version of
React (pretty likely), then the user wont have to download that version of react
more than once. This compounds across the number of teams and projects PayPal
has. And because I also write and maintain
&lt;a href="https://kentcdodds.com/blog/tools-without-config"&gt;paypal-scripts&lt;/a&gt;, I can build-in a really nice
process into paypal-scripts so people can get this functionality out of the box.
Automatic user experience improvement! Woo!&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;I have a lot of things on my plate, but I&amp;#x27;m hoping to be able to do this in the
next few months. I think it&amp;#x27;ll be a real win for people using PayPal products.
Can&amp;#x27;t wait to see those bundle sizes getting smaller! Good luck friends!&lt;/p&gt;&lt;p&gt;P.S. One other thing that I really love about unpkg is the index page for a
package. Simply add a &lt;code&gt;/&lt;/code&gt; at the end of the URL and you&amp;#x27;ll see an index of the
files as well as a version chooser which is pretty awesome:
&lt;a href="https://unpkg.com/d3"&gt;&lt;code&gt;https://unpkg.com/d3/&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Learn more about JavaScript from me&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://youtu.be/kTlcu16rSLc&amp;amp;list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;More than you want to know about ES6 Modules @ Learn to Code Websites and Apps Meetup (remote)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/t3R3R7UyN2Y&amp;amp;list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;ES6 and Beyond Workshop Part 1 at PayPal (Jan 2017)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/eOKQDh50ECU&amp;amp;list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;ES6 and Beyond Workshop Part 2 at PayPal (March 2017)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/workshops/#code-transformation-and-linting"&gt;Code Transformation and Linting&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/talks/#writing-custom-babel-and-eslint-plugins-with-asts"&gt;Writing custom Babel and ESLint plugins with ASTs&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://gh-polls.com"&gt;gh-polls.com&lt;/a&gt; — &amp;quot;GH polls is a quick and effective way
to request feedback from community members in GitHub issues.&amp;quot; by
&lt;a href="https://twitter.com/tjholowaychuk"&gt;TJ Holowaychuk&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;a href="https://there.pm"&gt;There&lt;/a&gt; — A really neat app by
&lt;a href="https://twitter.com/morajabi"&gt;Mo Rajabifard&lt;/a&gt; that&amp;#x27;ll tell you what time it is
for your friends and co-workers in a nice UI.&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/elbywan/wretch"&gt;wretch&lt;/a&gt; — &amp;quot;A tiny wrapper built around
fetch with an intuitive syntax. 🍬&amp;quot; by
&lt;a href="https://github.com/elbywan"&gt;Julien Elbaz&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/unpkg-an-open-source-cdn-for-npm"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Polyfill as needed with polyfill-service]]></title>
<description><![CDATA[In last week's newsletter "What is a polyfill" , I
talked about a situation I came across with a white screen on IE10 (the app
crashed because we were missing polyfills). I explained a bit of the difference
between a polyfill and a code transform. I…]]></description>
<link>https://kentcdodds.com/blog/polyfill-as-needed-with-polyfill-service</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/polyfill-as-needed-with-polyfill-service</guid>
<pubDate>Mon, 06 Aug 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;In last week&amp;#x27;s newsletter &lt;a href="https://kentcdodds.com/blog/what-is-a-polyfill"&gt;&amp;quot;What is a polyfill&amp;quot;&lt;/a&gt;, I
talked about a situation I came across with a white screen on IE10 (the app
crashed because we were missing polyfills). I explained a bit of the difference
between a polyfill and a code transform. I explained a few options you have at
your disposal to use new JavaScript features and still support older browsers.
In the conclusion I said this:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;So what did I do to fix my IE10 bug? Well, one thing that really bugs me is
that I have to ship all this code for polyfills to all browsers even if they&lt;/em&gt;
do &lt;em&gt;support these features. But a few years ago I heard of&lt;/em&gt; &amp;gt;
&lt;a href="https://polyfill.io"&gt;&lt;em&gt;a service&lt;/em&gt;&lt;/a&gt; &lt;em&gt;that was able to ship polyfills that are
relevant only to the browser requesting them. I created my own endpoint that
uses&lt;/em&gt; &lt;a href="https://github.com/Financial-Times/polyfill-service"&gt;&lt;em&gt;the module&lt;/em&gt;&lt;/a&gt; &amp;gt;
&lt;em&gt;that powers that service and I&amp;#x27;ll write about that next week!&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;That&amp;#x27;s today&amp;#x27;s newsletter! I&amp;#x27;ll explain how I created a &lt;code&gt;polyfill.js&lt;/code&gt; endpoint
that gives back a very aggressively cached JavaScript file with the polyfills
that users need and no more.&lt;/p&gt;&lt;h3&gt;Why polyfill-service?&lt;/h3&gt;&lt;p&gt;With the way I have my usage of polyfill-service configured today, if I make a
request for &lt;code&gt;polyfill.js&lt;/code&gt; using Internet Explorer 10 (the lowest version of IE
that we support), the response is 60.2kb! If you&amp;#x27;re unfamiliar with the impact
this can make, I suggest you read
&lt;a href="https://medium.com/dev-channel/the-cost-of-javascript-84009f51e99e"&gt;The Cost Of JavaScript&lt;/a&gt;
by &lt;a href="https://twitter.com/addyosmani"&gt;Addy Osmani&lt;/a&gt; (or
&lt;a href="https://youtu.be/63I-mEuSvGA"&gt;watch a talk version here&lt;/a&gt;). To put this in terms
you may appreciate, this will take users in emerging markets about a full second
just to download, then you have to take the content they&amp;#x27;ve downloaded and
parse/compile/run it which can take even longer especially for individuals using
lower-end phones.&lt;/p&gt;&lt;p&gt;The state of the art with polyfills is to include those polyfills in your
&lt;code&gt;bundle.js&lt;/code&gt;file (in fact, lots of apps are just using all of &lt;code&gt;core-js&lt;/code&gt; which is
&lt;a href="https://bundlephobia.com/result?p=core-js@2.5.7"&gt;84.2 kb of minified JS&lt;/a&gt;). This
means that every browser will need to download, parse, and run that JavaScript
regardless of what browser they&amp;#x27;re using. But let&amp;#x27;s take a look at
&lt;a href="https://caniuse.com/usage-table"&gt;browser usage statistics&lt;/a&gt;. Your stats may vary
depending on your users, but if your app is typical of the global averages, then
you have &lt;em&gt;maybe&lt;/em&gt; 5% of your users who need more than a handful of kbs worth of
polyfills. Most of your users will be using modern, evergreen browsers that
support most of the features you&amp;#x27;re using. So you&amp;#x27;re making users who are
running modern browsers pay a &amp;quot;tax&amp;quot; for your site supporting those 5% of users
who wont/can&amp;#x27;t upgrade.&lt;/p&gt;&lt;p&gt;If I run Chrome 67 on my &lt;code&gt;polyfill.js&lt;/code&gt; file, it comes back
&lt;a href="https://cdn.polyfill.io/v2/polyfill.min.js"&gt;basically empty&lt;/a&gt;. By using
polyfill-service, only the browsers which &lt;em&gt;need&lt;/em&gt; the polyfills receive them.
This means that they can use my app quicker and I&amp;#x27;m not taking up some of your
bandwidth to download stuff you don&amp;#x27;t need (which actually means saving people
actual dollars if they don&amp;#x27;t have unlimited data).&lt;/p&gt;&lt;p&gt;Another aspect of using something like polyfill-service is because my polyfills
live in a completely different file from my &lt;code&gt;bundle.js&lt;/code&gt;, I can have it cached
forever, so users only need to download it once and never need to download it
again. So even for users on bad networks, they&amp;#x27;ll benefit from not having to
expend resources re-downloading a file that will never change.&lt;/p&gt;&lt;h3&gt;Using polyfill-service&lt;/h3&gt;&lt;p&gt;The &lt;a href="https://polyfill.io"&gt;polyfill.io&lt;/a&gt; service from Financial Times is awesome,
but with no SLA (service level agreement), many companies can&amp;#x27;t rely on it for
mission-critical applications. Luckily, the module that powers it is completely
open source so you can set up your own service in-house in a pretty
straightforward way and that&amp;#x27;s exactly what I did.&lt;/p&gt;&lt;p&gt;With the app I&amp;#x27;m working on right now (&lt;a href="https://paypal.me"&gt;paypal.me&lt;/a&gt;), we have
a server that&amp;#x27;s responsible for some light server-rendering for SEO purposes.
Basically, our server is a NodeJS server using &lt;a href="http://krakenjs.com"&gt;KrakenJS&lt;/a&gt;
(a wrapper on top of &lt;a href="https://expressjs.com"&gt;express&lt;/a&gt;), so I added a
&lt;code&gt;get&lt;/code&gt;handler to the express app:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;app.get(&amp;#x27;/polyfill.js&amp;#x27;, getBrowserPolyfill)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And with the &lt;code&gt;getBrowserPolyfill&lt;/code&gt; is a typical express route handler:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;import polyfill from &amp;#x27;polyfill-service&amp;#x27;
async function getBrowserPolyfill(req, res) {
const script = await polyfill.getPolyfillString({
/* options */
})
res.set({
&amp;#x27;Content-Type&amp;#x27;: &amp;#x27;application/javascript;charset=utf-8&amp;#x27;,
&amp;#x27;Content-Length&amp;#x27;: script.length,
})
if (shouldCacheAggressively) {
res.setHeader(&amp;#x27;Cache-Control&amp;#x27;, &amp;#x27;immutable&amp;#x27;)
}
res.write(script)
res.end()
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There&amp;#x27;s a little bit more to it, but this is the basic idea. So let&amp;#x27;s talk about
a few aspects of this solution.&lt;/p&gt;&lt;h3&gt;User Agent&lt;/h3&gt;&lt;p&gt;So the polyfill-service module needs to know what the user agent string is to
determine what the &lt;code&gt;script&lt;/code&gt; string should be (which JavaScript polyfills to
include). So I pass &lt;code&gt;req.headers[&amp;#x27;user-agent&amp;#x27;]&lt;/code&gt; as that value, though I allow
the &lt;code&gt;ua&lt;/code&gt; query string to override this and I have a fallback to IE 9 just in
case. And in the case that polyfill-service encounters a user agent it doesn&amp;#x27;t
recognize, I have it configured to just treat it as if it needs all the
polyfills (via the &lt;code&gt;unknown: &amp;#x27;polyfill&amp;#x27;&lt;/code&gt; option).&lt;/p&gt;&lt;h3&gt;Features&lt;/h3&gt;&lt;p&gt;There are a LOT of features that polyfill-service supports out of the box. It
defaults to the most useful ones, but it&amp;#x27;s a good idea to configure it. At first
I thought: &amp;quot;Hey, let&amp;#x27;s just have it support everything.&amp;quot; But then I found out
that if you asked it to polyfill &lt;em&gt;everything&lt;/em&gt; it could, it&amp;#x27;ll get HUGE (mostly
because it actually supports &lt;code&gt;Intl&lt;/code&gt; with every language pack which is kinda
reeeally big). So I ended up with specifying &lt;code&gt;es2015&lt;/code&gt;, &lt;code&gt;es2016&lt;/code&gt;, &lt;code&gt;es2017&lt;/code&gt;,
&lt;code&gt;es2018&lt;/code&gt;, and &lt;code&gt;default-3.6&lt;/code&gt; as the features config. That&amp;#x27;s working great and
supports everything that I care to support.&lt;/p&gt;&lt;h3&gt;Caching&lt;/h3&gt;&lt;p&gt;This one&amp;#x27;s a bit interesting. So that &lt;code&gt;shouldCacheAggressively&lt;/code&gt; is a bit
dangerous, so here&amp;#x27;s what I do... Because we&amp;#x27;re server-rendering the page, I can
actually generate the URL for the polyfill. It ends up looking like this (for IE
11):&lt;/p&gt;&lt;pre&gt;&lt;code&gt;polyfill.js?v=2&amp;amp;ua=Mozilla%2F5.0%20(Windows%20NT%2011.0%3B%20WOW64%3B%20Trident%2F7.0%3B%20rv%3A11.0)%20like%20Gecko
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There are two query strings on there: &lt;code&gt;v&lt;/code&gt; which is associated to a &lt;code&gt;version&lt;/code&gt;
that I have hard-coded. This allows me to break the cache in the event of an
emergency if we need to change the config or something.&lt;/p&gt;&lt;p&gt;I also generate it with the &lt;code&gt;ua&lt;/code&gt; which is the user agent as part of the query
string for the &lt;code&gt;polyfill.js&lt;/code&gt; file. Remember how I mentioned earlier that I allow
the &lt;code&gt;uq&lt;/code&gt;query string to override &lt;code&gt;req.headers[&amp;#x27;user-agent&amp;#x27;]&lt;/code&gt;? So that&amp;#x27;s what
this is doing. The reason I do this is for caching. With such a specific URL, I
can safely cache this forever. If the user upgrades (or downgrades!?) their
browser, but the cache isn&amp;#x27;t deleted, then this URL is changed and the old
cached version isn&amp;#x27;t used.&lt;/p&gt;&lt;h3&gt;Extras&lt;/h3&gt;&lt;p&gt;One &lt;a href="https://twitter.com/kentcdodds/status/997228884864139264"&gt;&amp;quot;fun&amp;quot; experience&lt;/a&gt;
I had while building this involved polyfill-service not playing nice with the
way that babel transpiles classes. Follow that twitter thread and github issues
linked for a &amp;quot;fun&amp;quot; time of your own... 😅&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;I&amp;#x27;m excited about this and I&amp;#x27;m hoping to build a more official polyfill service
for more of PayPal applications to use it so folks can build applications with
the latest JavaScript features without worrying about whether older browsers
natively support what they&amp;#x27;re writing and without making users of modern
browsers pay a &amp;quot;tax&amp;quot; for users of older browsers.&lt;/p&gt;&lt;p&gt;Best of luck to you!&lt;/p&gt;&lt;p&gt;P.S. Soon after sending this newsletter,
&lt;a href="https://github.com/kddeisz"&gt;Kevin Deisz&lt;/a&gt; made
&lt;a href="https://github.com/CultureHQ/polyfill-lambda"&gt;an open source AWS Lambda service&lt;/a&gt;.
Pretty cool!&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Learn more about JavaScript from me&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://youtu.be/kTlcu16rSLc?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;More than you want to know about ES6 Modules @ Learn to Code Websites and Apps Meetup (remote)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/t3R3R7UyN2Y?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;ES6 and Beyond Workshop Part 1 at PayPal (Jan 2017)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/eOKQDh50ECU?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;ES6 and Beyond Workshop Part 2 at PayPal (March 2017)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/workshops/#code-transformation-and-linting"&gt;Code Transformation and Linting&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/talks/#writing-custom-babel-and-eslint-plugins-with-asts"&gt;Writing custom Babel and ESLint plugins with ASTs&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Also, don&amp;#x27;t forget to subscribe to &lt;a href="http://kcd.im/youtube"&gt;my youtube channel&lt;/a&gt;
for my daily devtips, like
&lt;a href="https://youtu.be/FsgGx1SMXn0?list=PLV5CVI1eNcJgCrPH_e6d57KRUTiDZgs0u"&gt;the one a while back where&lt;/a&gt;
I demo some advanced features of destructuring!&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://github.com/davidbanham/express-async-errors"&gt;&lt;code&gt;express-async-errors&lt;/code&gt;&lt;/a&gt; -
a nice package that allows me to use &lt;code&gt;async/await&lt;/code&gt;on express route
handlers/middleware without worrying about rejected promises being ignored and
making my server hang :)&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/2HnNo4t8534?t=541"&gt;ReactJS Denver: Confidently Testing React Apps&lt;/a&gt; — A
great talk at &lt;a href="https://www.meetup.com/ReactDenver"&gt;React Denver&lt;/a&gt; by
&lt;a href="https://twitter.com/mattparrish"&gt;Matt Parrish&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.robinwieruch.de/javascript-fundamentals-react-requirements"&gt;React is no abstraction, React is JavaScript&lt;/a&gt; — A
very interesting and important blog post from
&lt;a href="https://twitter.com/rwieruch"&gt;Robin Wieruch&lt;/a&gt; that teaches some common
JavaScript fundamentals that you&amp;#x27;ll need when working with React.&lt;/li&gt;&lt;li&gt;&lt;a href="https://medium.com/@ow/the-surface-book-2-is-everything-the-macbook-pro-should-be-5ef560edb505"&gt;The Surface Book 2 is everything the MacBook Pro should be&lt;/a&gt;
by &lt;a href="https://twitter.com/ow"&gt;Owen Williams&lt;/a&gt; — I&amp;#x27;m getting more and more
convinced that my next computer is NOT going to be a MacBook. Here&amp;#x27;s hoping
that the Surface Book can get me 32 GB of RAM before I need another computer!&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/polyfill-as-needed-with-polyfill-service"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[What is a polyfill]]></title>
<description><![CDATA[A few weeks back I found a bug with IE where all the user saw was a blank white
page. If you've been around for a while in the wonderful world of the
client-side SPA, you'll probably know what was wrong without thinking twice.
That's right. It was a…]]></description>
<link>https://kentcdodds.com/blog/what-is-a-polyfill</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/what-is-a-polyfill</guid>
<pubDate>Mon, 30 Jul 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;A few weeks back I found a bug with IE where all the user saw was a blank white
page. If you&amp;#x27;ve been around for a while in the wonderful world of the
client-side SPA, you&amp;#x27;ll probably know what was wrong without thinking twice.
That&amp;#x27;s right. It was a JavaScript error before client-side rendering happened.&lt;/p&gt;&lt;p&gt;Considering it the bug only rears its head in Internet Explorer, my first guess
is a problem with polyfills. Yep! That was it!&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Uncaught TypeError: contacts.includes is not a function
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But we&amp;#x27;re transpiling our code with Babel! Doesn&amp;#x27;t that mean that I can use all
the latest and greatest JavaScript I want without having to worry about whether
the browser supports it? Nope! Let&amp;#x27;s learn more...&lt;/p&gt;&lt;h3&gt;Polyfills vs Code Transforms&lt;/h3&gt;&lt;p&gt;JavaScript is constantly evolving thanks to the efforts of people in and around
&lt;a href="https://github.com/tc39"&gt;the TC39&lt;/a&gt;. Some of the evolutions rely on new syntax
(like
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions"&gt;arrow functions&lt;/a&gt;)
which allows me to do this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;const addOne = num =&amp;gt; num + 1
if (addOne(2) &amp;gt; 2) {
console.log(&amp;#x27;Math. Wow!&amp;#x27;)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Often, we can use this syntax in our source code so long as we convert it to
syntax that can run in the browser (for example, by using a transpiler such as
&lt;a href="https://babeljs.io"&gt;babel&lt;/a&gt;:
&lt;a href="http://babeljs.io/repl/#?babili=false&amp;amp;browsers=ie%2010&amp;amp;build=&amp;amp;builtIns=false&amp;amp;spec=false&amp;amp;loose=false&amp;amp;code_lz=MYewdgzgLgBAhgEwQeTAUxgXhmArgWywD4cCYBqGARgCgBLAMxgApEV1mAmAShhJ5gBvGjBihIIADZoAdJJABzZgHIAsnCgALGTADqIAO4BCZdxoBfGkA&amp;amp;debug=false&amp;amp;forceAllTransforms=false&amp;amp;shippedProposals=false&amp;amp;circleciRepo=&amp;amp;evaluate=true&amp;amp;fileSize=false&amp;amp;sourceType=module&amp;amp;lineWrap=true&amp;amp;presets=env&amp;amp;prettier=false&amp;amp;targets=&amp;amp;version=6.26.0&amp;amp;envVersion=1.6.2"&gt;example transpiled in the browser with babel-preset-env&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;Some other of these new features rely on new APIs, like
&lt;code&gt;Array.prototype.includes&lt;/code&gt; which allows me to do this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;const contacts = [&amp;#x27;Brooke&amp;#x27;, &amp;#x27;Becca&amp;#x27;, &amp;#x27;Nathan&amp;#x27;, &amp;#x27;Adam&amp;#x27;, &amp;#x27;Michael&amp;#x27;]
if (contacts.includes(&amp;#x27;Rachel&amp;#x27;)) {
console.log(&amp;#x27;You have a Rachel!&amp;#x27;)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With these, if you
&lt;a href="http://babeljs.io/repl/#?babili=false&amp;amp;browsers=ie%2010&amp;amp;build=&amp;amp;builtIns=false&amp;amp;spec=false&amp;amp;loose=false&amp;amp;code_lz=MYewdgzgLgBKZQIbChGBeGBtA5AIQCcQQBrAUxwBoZ8zhhEqaA5RKAC0TCZwEEATRAFseAWQCWwTmQA2OALoAocQDMYACnhIUEAHTiwwGQFd-ZCOpwAlZO1k4AlA5gBvRTDjgIIGWV0yQAHNLAE0QYxhOADcyGEQYGylZAEJHRQBfRSA&amp;amp;debug=false&amp;amp;forceAllTransforms=false&amp;amp;shippedProposals=false&amp;amp;circleciRepo=&amp;amp;evaluate=true&amp;amp;fileSize=false&amp;amp;sourceType=module&amp;amp;lineWrap=true&amp;amp;presets=env&amp;amp;prettier=false&amp;amp;targets=&amp;amp;version=6.26.0&amp;amp;envVersion=1.6.2"&gt;run them through babel&amp;#x27;s env preset&lt;/a&gt;
the &lt;code&gt;includes&lt;/code&gt; function is not transpiled because it&amp;#x27;s not a syntax issue, but a
built-in API one and babel&amp;#x27;s env preset only includes transforms for syntax
transformations. You &lt;em&gt;could&lt;/em&gt;
&lt;a href="https://kentcdodds.com/talks/#writing-custom-babel-and-eslint-plugins-with-asts"&gt;write your own babel plugin&lt;/a&gt;
(&lt;a href="https://astexplorer.net/#/gist/538b72e2af148a14d7c0f5824b431cd6/47a57f42697199d6cfa1d4b1027951ef170a980e"&gt;like this&lt;/a&gt;)
to transform the code, but for &lt;em&gt;some&lt;/em&gt; APIs it just wouldn&amp;#x27;t be practical because
the transformed version would be significantly complex.&lt;/p&gt;&lt;p&gt;A polyfill is code which will make the currently running JavaScript environment
support features which it does not. For example, a (imperfect) polyfill for
&lt;code&gt;includes&lt;/code&gt; might look something like this
(&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes"&gt;refer to MDN&lt;/a&gt;
for a real polyfill):&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;if (!Array.prototype.includes) {
Array.prototype.includes = function includes(searchElement) {
return this.indexOf(searchElement) !== -1
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;if&lt;/code&gt; statement is there to make this a &amp;quot;gated&amp;quot; polyfill. That means that if
the functionality already exists, the polyfill code will &lt;em&gt;not&lt;/em&gt; override the
pre-existing behavior. You may consider this to be desirable, but it&amp;#x27;s actually
the reason that &lt;code&gt;includes&lt;/code&gt;is not called &lt;code&gt;contains&lt;/code&gt; on &lt;code&gt;String.prototype&lt;/code&gt; (TL;DR:
some versions of mootools implemented &lt;code&gt;contains&lt;/code&gt; in a gated fashion but the
implementation is different from how &lt;code&gt;includes&lt;/code&gt; works so the TC39 had to change
the name to not break tons of websites).&lt;/p&gt;&lt;p&gt;The part that assigns &lt;code&gt;Array.prototype.includes&lt;/code&gt; to a function is called
&amp;quot;monkey-patching&amp;quot; 🐒 By applying this to the prototype, we&amp;#x27;re adding &lt;code&gt;includes&lt;/code&gt;
support to all arrays in the app
(&lt;a href="https://github.com/getify/You-Dont-Know-JS/blob/f0d591b6502c080b92e18fc470432af8144db610/this%20%26%20object%20prototypes/ch5.md"&gt;learn more about prototypes here&lt;/a&gt;).
Effectively, the polyfill&amp;#x27;s job is to make it so I can use the JavaScript
feature without worrying about whether it&amp;#x27;s supported by the environment in
which my code is running (like IE 10 for example).&lt;/p&gt;&lt;h3&gt;Where to get transforms and polyfills&lt;/h3&gt;&lt;p&gt;With syntax transforms, I recommend
&lt;a href="https://babeljs.io/docs/en/next/babel-preset-env.html"&gt;babel-preset-env&lt;/a&gt;. It&amp;#x27;s
actually fairly straightforward. For polyfills, the most popular one is
&lt;a href="https://www.npmjs.com/package/core-js"&gt;&lt;code&gt;core-js&lt;/code&gt;&lt;/a&gt;. You might also look at
&lt;a href="https://babeljs.io/docs/en/next/babel-polyfill.html"&gt;&lt;code&gt;babel-polyfill&lt;/code&gt;&lt;/a&gt; which
uses &lt;code&gt;core-js&lt;/code&gt; and a custom &lt;code&gt;regenerator runtime&lt;/code&gt; to support generators and
async/await the way that babel transpiles it. Polyfills are sometimes referred
to as &amp;quot;shims&amp;quot; and you may be interested in the
&lt;a href="https://github.com/airbnb/js-shims"&gt;&lt;code&gt;js-shims&lt;/code&gt;&lt;/a&gt; by airbnb (which I&amp;#x27;ve been told
are more spec-complient than &lt;code&gt;core-js&lt;/code&gt;).&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;So what did I do to fix my IE10 bug? Well, one thing that really bugs me is that
I have to ship all this code for polyfills to all browsers even if they &lt;em&gt;do&lt;/em&gt;
support these features. But a few years ago I heard of
&lt;a href="https://polyfill.io"&gt;a service&lt;/a&gt; that was able to ship polyfills that are
relevant only to the browser requesting them. I created my own endpoint that
uses &lt;a href="https://github.com/Financial-Times/polyfill-service"&gt;the module&lt;/a&gt; that
powers that service and I&amp;#x27;ll write about that next week!&lt;/p&gt;&lt;p&gt;I hope this is helpful! Good luck!&lt;/p&gt;&lt;p&gt;P.S. You may have heard of something called a &amp;quot;ponyfill.&amp;quot; Ponyfills are similar
to polyfills except they don&amp;#x27;t monkey-patch, instead they&amp;#x27;re just the function
by itself and allow you to call them directly.
&lt;a href="https://github.com/sindresorhus/ponyfill"&gt;Learn more about ponyfills&lt;/a&gt;. In
general, I&amp;#x27;m more in favor of ponyfills, though you just can&amp;#x27;t get away from
polyfills completely because often your dependencies are relying on built-ins
that your browsers don&amp;#x27;t support.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Learn more about React from me&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://kcd.im/beginner-react"&gt;The Beginner&amp;#x27;s Guide to React&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://kcd.im/advanced-react"&gt;Advanced React Component Patterns&lt;/a&gt; (also on
&lt;a href="https://frontendmasters.com/courses/advanced-react-patterns"&gt;Frontend Masters&lt;/a&gt;).&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://github.com/testdouble/cypress-capybara"&gt;cypress-capybara&lt;/a&gt; — If you&amp;#x27;ve
used &lt;a href="https://github.com/teamcapybara/capybara"&gt;capybara&lt;/a&gt; before you&amp;#x27;ll
probably love this util from &lt;a href="https://twitter.com/searls"&gt;Justin Searls&lt;/a&gt;. If
you like this, then you&amp;#x27;ll probably love
&lt;a href="https://github.com/testing-library/cypress-testing-library"&gt;cypress-testing-library&lt;/a&gt;.
In any case,
&lt;a href="https://kentcdodds.com/blog/making-your-ui-tests-resilient-to-change"&gt;don&amp;#x27;t reuse your CSS selectors as test selectors&lt;/a&gt;!&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/joshwcomeau/guppy"&gt;guppy&lt;/a&gt; — 🐠A friendly application
manager and task runner for React.js by
&lt;a href="https://twitter.com/joshwcomeau"&gt;Josh Comeau&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;a href="https://twitter.com/CompuIves/status/1018871036719325184"&gt;Themes Support in Codesandbox&lt;/a&gt;
🤩 — &lt;a href="http://kcd.im/mft"&gt;I set mine to Night Owl and Dank.sh&lt;/a&gt; so fast you
wouldn&amp;#x27;t believe it. That &lt;a href="https://twitter.com/CompuIves"&gt;Ives van Hoorne&lt;/a&gt; has
gone and done some amazing work again!&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/what-is-a-polyfill"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Why I Never Use Shallow Rendering]]></title>
<description><![CDATA[I remember a few years ago when I got started with React I decided I needed to
figure out how to test React components. I tried
shallow from enzyme and
immediately decided that I would never use it to test my React components. I've
expressed this…]]></description>
<link>https://kentcdodds.com/blog/why-i-never-use-shallow-rendering</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/why-i-never-use-shallow-rendering</guid>
<pubDate>Mon, 23 Jul 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;I remember a few years ago when I got started with React I decided I needed to
figure out how to test React components. I tried
&lt;a href="http://airbnb.io/enzyme/docs/api/shallow.html"&gt;&lt;code&gt;shallow&lt;/code&gt;&lt;/a&gt; from enzyme and
immediately decided that I would never use it to test my React components. I&amp;#x27;ve
expressed this feeling on many occasions and get asked on a regular basis why I
feel the way I do about &lt;code&gt;shallow&lt;/code&gt; rendering and why
&lt;a href="https://github.com/testing-library/react-testing-library"&gt;&lt;code&gt;react-testing-library&lt;/code&gt;&lt;/a&gt;
will never support &lt;code&gt;shallow&lt;/code&gt; rendering.&lt;/p&gt;&lt;p&gt;So finally I&amp;#x27;m coming out with it and explaining why I never use shallow
rendering and why I think nobody else should either. Here&amp;#x27;s my main assertion:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;With shallow rendering, I can refactor my component&amp;#x27;s implementation and my
tests break. With shallow rendering, I can break my application and my tests
say everything&amp;#x27;s still working.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;This is highly concerning to me because not only does it make testing
frustrating, but it also lulls you into a false sense of security. &lt;strong&gt;The reason
I write tests is to be confident that my application works and there are far
better ways to do that than shallow rendering.&lt;/strong&gt;&lt;/p&gt;&lt;h3&gt;What even is shallow rendering?&lt;/h3&gt;&lt;p&gt;For the purposes of this article, let&amp;#x27;s use this example as our subject under
test:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;import React from &amp;#x27;react&amp;#x27;
import {CSSTransition} from &amp;#x27;react-transition-group&amp;#x27;
function Fade({children, ...props}) {
return (
&amp;lt;CSSTransition {...props} timeout={1000} className=&amp;quot;fade&amp;quot;&amp;gt;
{children}
&amp;lt;/CSSTransition&amp;gt;
)
}
class HiddenMessage extends React.Component {
static defaultProps = {initialShow: false}
state = {show: this.props.initialShow}
toggle = () =&amp;gt; {
this.setState(({show}) =&amp;gt; ({show: !show}))
}
render() {
return (
&amp;lt;div&amp;gt;
&amp;lt;button onClick={this.toggle}&amp;gt;Toggle&amp;lt;/button&amp;gt;
&amp;lt;Fade in={this.state.show}&amp;gt;
&amp;lt;div&amp;gt;Hello world&amp;lt;/div&amp;gt;
&amp;lt;/Fade&amp;gt;
&amp;lt;/div&amp;gt;
)
}
}
export {HiddenMessage}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here&amp;#x27;s an example of a test that uses shallow rendering with enzyme:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;import React from &amp;#x27;react&amp;#x27;
import Enzyme, {shallow} from &amp;#x27;enzyme&amp;#x27;
import Adapter from &amp;#x27;enzyme-adapter-react-16&amp;#x27;
import {HiddenMessage} from &amp;#x27;../hidden-message&amp;#x27;
Enzyme.configure({adapter: new Adapter()})
test(&amp;#x27;shallow&amp;#x27;, () =&amp;gt; {
const wrapper = shallow(&amp;lt;HiddenMessage initialShow={true} /&amp;gt;)
expect(wrapper.find(&amp;#x27;Fade&amp;#x27;).props()).toEqual({
in: true,
children: &amp;lt;div&amp;gt;Hello world&amp;lt;/div&amp;gt;,
})
wrapper.find(&amp;#x27;button&amp;#x27;).simulate(&amp;#x27;click&amp;#x27;)
expect(wrapper.find(&amp;#x27;Fade&amp;#x27;).props()).toEqual({
in: false,
children: &amp;lt;div&amp;gt;Hello world&amp;lt;/div&amp;gt;,
})
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To understand shallow rendering, let&amp;#x27;s add a &lt;code&gt;console.log(wrapper.debug())&lt;/code&gt;
which will log out the structure of what enzyme has rendered for us:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;&amp;lt;div&amp;gt;
&amp;lt;button onClick={[Function]}&amp;gt;Toggle&amp;lt;/button&amp;gt;
&amp;lt;Fade in={true}&amp;gt;
&amp;lt;div&amp;gt;Hello world&amp;lt;/div&amp;gt;
&amp;lt;/Fade&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You&amp;#x27;ll notice that it&amp;#x27;s not actually showing the &lt;code&gt;CSSTransition&lt;/code&gt; which is what
&lt;code&gt;Fade&lt;/code&gt; is rendering. This is because instead of actually rendering components
and calling into the &lt;code&gt;Fade&lt;/code&gt; component, shallow just looks at the props that
would be applied to the React elements created by the component you&amp;#x27;re shallowly
rendering. In fact, if I were to take the &lt;code&gt;render&lt;/code&gt; method of the &lt;code&gt;HiddenMessage&lt;/code&gt;
component and &lt;code&gt;console.log&lt;/code&gt; what it&amp;#x27;s returning, I&amp;#x27;d get something that looks a
bit like this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;{
&amp;quot;type&amp;quot;: &amp;quot;div&amp;quot;,
&amp;quot;props&amp;quot;: {
&amp;quot;children&amp;quot;: [
{
&amp;quot;type&amp;quot;: &amp;quot;button&amp;quot;,
&amp;quot;props&amp;quot;: {
&amp;quot;onClick&amp;quot;: [Function],
&amp;quot;children&amp;quot;: &amp;quot;Toggle&amp;quot;
}
},
{
&amp;quot;type&amp;quot;: [Function: Fade],
&amp;quot;props&amp;quot;: {
&amp;quot;in&amp;quot;: true,
&amp;quot;children&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;div&amp;quot;,
&amp;quot;props&amp;quot;: {
&amp;quot;children&amp;quot;: &amp;quot;Hello world&amp;quot;
}
}
}
}
]
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Look familiar? So all shallow rendering is doing is taking the result of the
given component&amp;#x27;s &lt;code&gt;render&lt;/code&gt; method (which will be a React element (read
&lt;a href="https://kentcdodds.com/blog/what-is-jsx"&gt;What is JSX?&lt;/a&gt;)) and giving us a &lt;code&gt;wrapper&lt;/code&gt; object with some
utilities for traversing this JavaScript object. This means it doesn&amp;#x27;t run
lifecycle methods (because we just have the React elements to deal with), it
doesn&amp;#x27;t allow you to actually interact with DOM elements (because nothing&amp;#x27;s
actually rendered), and it doesn&amp;#x27;t actually attempt to get the react elements
that are returned by your custom components (like our &lt;code&gt;Fade&lt;/code&gt; component).&lt;/p&gt;&lt;h3&gt;Why people use shallow rendering&lt;/h3&gt;&lt;p&gt;When I determined early on to never use shallow rendering, it was because I knew
that there were better ways to get at the things that shallow rendering makes
easy without making the trade-offs shallow rendering forces you to make.
&lt;a href="https://twitter.com/kentcdodds/status/1016084196421296133"&gt;I recently asked folks&lt;/a&gt;
to tell me why they use shallow rendering. Here are a few of the things that
shallow rendering makes easier:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="https://twitter.com/Raed667/status/1016095856481701888"&gt;... for calling methods in React components&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://twitter.com/MattTrifilo/status/1016101577667403778"&gt;... it seems like a waste to render all of the children of each component under test, for every test, hundreds/thousands of times...&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://twitter.com/janhoogeveen/status/1016207627859251200"&gt;For actual unit testing. Testing composed components introduces new dependencies that might trigger an error while the unit itself might still work as intended.&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;There were more responses, but these sum up the main arguments for using shallow
rendering. Let&amp;#x27;s address each of these:&lt;/p&gt;&lt;h3&gt;Calling methods in react components&lt;/h3&gt;&lt;p&gt;Have you ever seen or written a test that looks like this?&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;test(&amp;#x27;toggle toggles the state of show&amp;#x27;, () =&amp;gt; {
const wrapper = shallow(&amp;lt;HiddenMessage initialShow={true} /&amp;gt;)
expect(wrapper.state().show).toBe(true) // initialized properly
wrapper.instance().toggle()
wrapper.update()
expect(wrapper.state().show).toBe(false) // toggled
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is a great reason to use shallow rendering, but it&amp;#x27;s a really poor testing
practice. There are two really important things that I try to consider when
testing:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Will this test break when there&amp;#x27;s a mistake that would break the component
in production?&lt;/li&gt;&lt;li&gt;Will this test continue to work when there&amp;#x27;s a fully backward compatible
refactor of the component?&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;This kind of test fails both of those considerations:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;I could mistakenly set &lt;code&gt;onClick&lt;/code&gt; of the &lt;code&gt;button&lt;/code&gt; to &lt;code&gt;this.tgogle&lt;/code&gt; instead of
&lt;code&gt;this.toggle&lt;/code&gt;. My test continues to work, but my component is broken.&lt;/li&gt;&lt;li&gt;I could rename &lt;code&gt;toggle&lt;/code&gt; to &lt;code&gt;handleButtonClick&lt;/code&gt; (and update the corresponding
&lt;code&gt;onClick&lt;/code&gt; reference). My test breaks despite this being a refactor.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;The reason this kind of test fails those considerations is because it&amp;#x27;s testing
irrelevant implementation details. The user doesn&amp;#x27;t care one bit what things are
called. In fact, that test doesn&amp;#x27;t even verify that the message is hidden
properly when the &lt;code&gt;show&lt;/code&gt; state is &lt;code&gt;false&lt;/code&gt; or shown when the &lt;code&gt;show&lt;/code&gt; state is
&lt;code&gt;true&lt;/code&gt;. So not only does the test not do a great job keeping us safe from
breakages, it&amp;#x27;s also flakey and doesn&amp;#x27;t actually test the reason the component
exists in the first place.&lt;/p&gt;&lt;p&gt;In summary, if your test uses &lt;code&gt;instance()&lt;/code&gt; or &lt;code&gt;state()&lt;/code&gt;, know that you&amp;#x27;re
testing things that the user couldn&amp;#x27;t possibly know about or even care about,
which will take your tests further from giving you confidence that things will
work when your user uses them.&lt;/p&gt;&lt;h3&gt;... it seems like a waste ...&lt;/h3&gt;&lt;p&gt;There&amp;#x27;s no getting around the fact that shallow rendering is faster than any
other form of testing react components. It&amp;#x27;s certainly way faster than mounting
a react component. But we&amp;#x27;re talking a handful of milliseconds here. Yes, it
will add up, but I&amp;#x27;d gladly wait an extra few seconds or minutes for my tests to
finish in exchange for my tests actually giving me confidence that my
application will work when I ship it to users.&lt;/p&gt;&lt;p&gt;In addition to this, you should probably use Jest&amp;#x27;s capabilities for only
running tests relevant to your changes while developing your tests so the
difference wont be perceivable when running the test suite locally.&lt;/p&gt;&lt;h3&gt;For actual unit testing&lt;/h3&gt;&lt;p&gt;This is a very common misconception: &amp;quot;To unit test a react component you must
use shallow rendering so other components are not rendered.&amp;quot; It&amp;#x27;s true that
shallow rendering doesn&amp;#x27;t render other components (as demonstrated above),
what&amp;#x27;s wrong with this is that it&amp;#x27;s way too heavy handed because it doesn&amp;#x27;t
render &lt;em&gt;any&lt;/em&gt; other components. You don&amp;#x27;t get a choice.&lt;/p&gt;&lt;p&gt;Not only does shallow rendering not render third party components, it doesn&amp;#x27;t
even render in-file components. For example, the &lt;code&gt;&amp;lt;Fade /&amp;gt;&lt;/code&gt; component we have
above is an implementation detail of the &lt;code&gt;&amp;lt;HiddenMessage /&amp;gt;&lt;/code&gt; component, but
because we&amp;#x27;re shallow rendering &lt;code&gt;&amp;lt;Fade /&amp;gt;&lt;/code&gt; isn&amp;#x27;t rendered so changes to that
component could break our application but not our test. That&amp;#x27;s a major issue in
my mind and is evidence to me that we&amp;#x27;re testing implementation details.&lt;/p&gt;&lt;p&gt;In addition, you can &lt;em&gt;definitely&lt;/em&gt; unit test react components without shallow
rendering. Checkout the section near the end for an example of such a test (uses
react-testing-library, but you could do this with enzyme as well) that uses Jest
mocking to mock out the &lt;code&gt;&amp;lt;CSSTransition /&amp;gt;&lt;/code&gt; component.&lt;/p&gt;&lt;p&gt;I should add that I generally am against mocking even third party components
100% of the time. The argument for mocking third party components I often hear
is
&lt;a href="https://twitter.com/janhoogeveen/status/1016207627859251200"&gt;Testing composed components introduces new dependencies that might trigger an error while the unit itself might still work as intended.&lt;/a&gt;.
But isn&amp;#x27;t the point of testing to be confident the application works? Who cares
if your unit works if the app is broken? I &lt;em&gt;definitely&lt;/em&gt; want to know if the
third party component I&amp;#x27;m using breaks my use case. I mean, I&amp;#x27;m not going to
rewrite their entire test base, but if I can easily test my use case by &lt;em&gt;not&lt;/em&gt;
mocking out their component then why not do that and get the extra confidence?&lt;/p&gt;&lt;p&gt;I should also add that
&lt;a href="http://kcd.im/write-tests"&gt;I&amp;#x27;m in favor of relying more heavily on integration testing&lt;/a&gt;.
When you do this, you need to unit test fewer of your simple components and wind
up only having to unit test edge cases for components (which can mock all they
want). But even in these situations, I still think it leads to more confidence
and a more maintainable testbase when you&amp;#x27;re explicit about which components are
being mocked and which are being rendered by doing full mounting and explicit
mocks.&lt;/p&gt;&lt;h3&gt;Without shallow rendering&lt;/h3&gt;&lt;p&gt;I&amp;#x27;m a huge believer of the guiding principle of
&lt;a href="https://github.com/testing-library/react-testing-library"&gt;&lt;code&gt;react-testing-library&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;a href="https://twitter.com/kentcdodds/status/977018512689455106"&gt;&lt;em&gt;The more your tests resemble the way your software is used, the more confidence they can give you.&lt;/em&gt;&lt;/a&gt;&lt;em&gt; — Kent
C. Dodds 👋&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;That&amp;#x27;s why I wrote the library in the first place. As a side-note to this
shallow rendering post, I want to mention there are fewer ways for you to do
things that are impossible for the user to do. Here&amp;#x27;s the list of things that
react-testing-library cannot do (out of the box):&lt;/p&gt;&lt;ol&gt;&lt;li&gt;shallow rendering&lt;/li&gt;&lt;li&gt;Static rendering (like enzyme&amp;#x27;s
&lt;a href="http://airbnb.io/enzyme/docs/api/render.html"&gt;&lt;code&gt;render&lt;/code&gt;&lt;/a&gt; function).&lt;/li&gt;&lt;li&gt;Pretty much most of enzyme&amp;#x27;s methods to query elements (like
&lt;a href="http://airbnb.io/enzyme/docs/api/ReactWrapper/find.html"&gt;&lt;code&gt;find&lt;/code&gt;&lt;/a&gt;) which
include the ability to find by a component class or even its &lt;code&gt;displayName&lt;/code&gt;
(again, the user does not care what your component is called and neither
should your test). Note: react-testing-library supports querying for
elements in ways that encourage accessibility in your components and more
maintainable tests.&lt;/li&gt;&lt;li&gt;Getting a component instance (like enzyme&amp;#x27;s
&lt;a href="http://airbnb.io/enzyme/docs/api/ReactWrapper/instance.html"&gt;&lt;code&gt;instance&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;Getting and setting a component&amp;#x27;s props (&lt;code&gt;props()&lt;/code&gt;)&lt;/li&gt;&lt;li&gt;Getting and setting a component&amp;#x27;s state (&lt;code&gt;state()&lt;/code&gt;)&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;All of these things are things which users of your component cannot do, so your
tests shouldn&amp;#x27;t do them either. Below is a test of the &lt;code&gt;&amp;lt;HiddenMessage /&amp;gt;&lt;/code&gt;
component which resembles the way a user would use your component much more
closely. In addition, it can verify that you&amp;#x27;re using &lt;code&gt;&amp;lt;CSSTransition /&amp;gt;&lt;/code&gt;
properly (something the shallow rendering example was &lt;em&gt;incapable&lt;/em&gt; of doing).&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;import &amp;#x27;react-testing-library/cleanup-after-each&amp;#x27;
import React from &amp;#x27;react&amp;#x27;
import {CSSTransition} from &amp;#x27;react-transition-group&amp;#x27;
import {render, fireEvent} from &amp;#x27;react-testing-library&amp;#x27;
import {HiddenMessage} from &amp;#x27;../hidden-message&amp;#x27;
// NOTE: you do NOT have to do this in every test.
// Learn more about Jest&amp;#x27;s __mocks__ directory:
// https://jestjs.io/docs/en/manual-mocks
jest.mock(&amp;#x27;react-transition-group&amp;#x27;, () =&amp;gt; {
return {
CSSTransition: jest.fn(({children, in: show}) =&amp;gt; (show ? children : null)),
}
})
test(&amp;#x27;you can mock things with jest.mock&amp;#x27;, () =&amp;gt; {
const {getByText, queryByText} = render(&amp;lt;HiddenMessage initialShow={true} /&amp;gt;)
const toggleButton = getByText(/toggle/i)
const context = expect.any(Object)
const children = expect.any(Object)
const defaultProps = {children, timeout: 1000, className: &amp;#x27;fade&amp;#x27;}
expect(CSSTransition).toHaveBeenCalledWith(
{in: true, ...defaultProps},
context,
)
expect(getByText(/hello world/i)).not.toBeNull()
CSSTransition.mockClear()
fireEvent.click(toggleButton)
expect(queryByText(/hello world/i)).toBeNull()
expect(CSSTransition).toHaveBeenCalledWith(
{in: false, ...defaultProps},
context,
)
})
&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;A few weeks ago, my &lt;a href="http://kcd.im/devtips"&gt;DevTipsWithKent&lt;/a&gt; (my weekdaily
livestream on &lt;a href="http://kcd.im/youtube"&gt;YouTube&lt;/a&gt;) I livestreamed
&amp;quot;&lt;a href="https://youtu.be/LHUdxkThTM0?list=PLV5CVI1eNcJgCrPH_e6d57KRUTiDZgs0u"&gt;Migrating from shallow rendering react components to explicit component mocks&lt;/a&gt;&amp;quot;.
In that I demonstrate some of the pitfalls of shallow rendering I describe above
as well as how to use jest mocking instead.&lt;/p&gt;&lt;p&gt;I hope this is helpful! We&amp;#x27;re all just trying our best to deliver an awesome
experience to users. I wish you luck in that endeavor!&lt;/p&gt;&lt;h4&gt;P.S.&lt;/h4&gt;&lt;p&gt;Someone brought this up after I emailed my newsletter out:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Shallow wrapper is good to test small independent components. With proper
serializer it allows to have clear and understandable snapshots.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I very rarely use snapshot testing with react and I certainly wouldn&amp;#x27;t use it
with shallow. That&amp;#x27;s a recipe for implementation details. The whole snapshot is
nothing but implementation details (it&amp;#x27;s full of component and prop names that
change all the time on refactors). It&amp;#x27;ll fail any time you touch the component
and the git diff for the snapshot will look almost identical to the one for your
changes to the component.&lt;/p&gt;&lt;p&gt;This will make people careless about to the snapshot updates because they change
all the time. So it&amp;#x27;s basically worthless (almost worse than no tests because it
makes you think you&amp;#x27;re covered when you&amp;#x27;re not and you won&amp;#x27;t write proper tests
because they&amp;#x27;re in place).&lt;/p&gt;&lt;p&gt;I do think that snapshots can be useful though. For more about this from me,
checkout another blog post:&lt;/p&gt;&lt;p&gt;&lt;a href="https://kentcdodds.com/blog/effective-snapshot-testing"&gt;&lt;strong&gt;Effective Snapshot Testing&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I hope that helps!&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Learn more about testing from me&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://frontendmasters.com"&gt;Frontend Masters&lt;/a&gt;:
&lt;a href="https://frontendmasters.com/workshops/testing-practices-principles"&gt;Testing Practices and Principles&lt;/a&gt;
&amp;amp;
&lt;a href="https://frontendmasters.com/courses/testing-react"&gt;Testing React Applications&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://egghead.io/lessons/react-confidently-ship-production-react-apps"&gt;Confidently Ship Production React Apps&lt;/a&gt; — Something
new on &lt;a href="http://egghead.io"&gt;egghead.io&lt;/a&gt;. It&amp;#x27;s a recording of one of my talks
especially for &lt;a href="http://egghead.io"&gt;egghead.io&lt;/a&gt;. I think you&amp;#x27;ll really enjoy it
(and it&amp;#x27;s 🆓)&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/Fha2bVoC8SE?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;Write tests. Not too many. Mostly integration.&lt;/a&gt; — My
talk at Assert.js conference
(&lt;a href="http://kcd.im/write-tests"&gt;and here&amp;#x27;s the blog post&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/VQZx1Z3sW0E?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;Testing Practices and Principles&lt;/a&gt; — A
recording of my workshop at Assert.js&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://youtu.be/8BNdxFzMeVg&amp;amp;list=PLV5CVI1eNcJgCrPH_e6d57KRUTiDZgs0u"&gt;Avoid setState warnings on unmounted React components&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/3AaghqS3W4Y&amp;amp;list=PLV5CVI1eNcJgCrPH_e6d57KRUTiDZgs0u"&gt;Magic Move effect with JavaScript&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/why-i-never-use-shallow-rendering"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[What is JSX?]]></title>
<description><![CDATA[I think a critical part of understanding how to use React effectively is
understanding JavaScript and JavaScript expressions. So I'm going to show you a
few examples of JSX and it's compiled version to help give you an idea of how
this all works. As…]]></description>
<link>https://kentcdodds.com/blog/what-is-jsx</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/what-is-jsx</guid>
<pubDate>Mon, 09 Jul 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;I think a critical part of understanding how to use React effectively is
understanding JavaScript and JavaScript expressions. So I&amp;#x27;m going to show you a
few examples of JSX and it&amp;#x27;s compiled version to help give you an idea of how
this all works. As soon as you can compile JSX in your head, you can use the
abstraction more powerfully.&lt;/p&gt;&lt;p&gt;Here&amp;#x27;s our simplest example:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Note, all examples assign to a variable &lt;code&gt;ui&lt;/code&gt; just to illustrate that these are
regular JavaScript expressions that you can assign to a variable.&lt;/p&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;ui = &amp;lt;div id=&amp;quot;root&amp;quot;&amp;gt;Hello world&amp;lt;/div&amp;gt;
ui = React.createElement(&amp;#x27;div&amp;#x27;, {id: &amp;#x27;root&amp;#x27;}, &amp;#x27;Hello world&amp;#x27;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As shown above, the JSX is compiled to &lt;code&gt;React.createElement&lt;/code&gt;. The API to
&lt;code&gt;React.createElement&lt;/code&gt; is:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;function createElement(elementType, props, ...children) {}
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;elementType&lt;/code&gt; can be a string or a function (class) for the type of element to
be created&lt;/li&gt;&lt;li&gt;&lt;code&gt;props&lt;/code&gt; is an object for the props we want applied to the element (or &lt;code&gt;null&lt;/code&gt;
if we specify no props)&lt;/li&gt;&lt;li&gt;&lt;code&gt;...children&lt;/code&gt; is all the children we want applied to the element too. This is
just a convenience and we could write an equivalent to above with:&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class="language-js"&gt;ui = React.createElement(&amp;#x27;div&amp;#x27;, {id: &amp;#x27;root&amp;#x27;, children: &amp;#x27;Hello world&amp;#x27;})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you have more than one child then you use an array:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;ui = (
&amp;lt;div&amp;gt;
&amp;lt;span&amp;gt;Hello&amp;lt;/span&amp;gt; &amp;lt;span&amp;gt;World&amp;lt;/span&amp;gt;
&amp;lt;/div&amp;gt;
)
ui = React.createElement(&amp;#x27;div&amp;#x27;, {
children: [
React.createElement(&amp;#x27;span&amp;#x27;, null, &amp;#x27;Hello&amp;#x27;),
&amp;#x27; &amp;#x27;,
React.createElement(&amp;#x27;span&amp;#x27;, null, &amp;#x27;World&amp;#x27;),
],
})
// Note: babel uses the third argument for children:
ui = React.createElement(
&amp;#x27;div&amp;#x27;, // type
null, // props
// children are the rest:
React.createElement(&amp;#x27;span&amp;#x27;, null, &amp;#x27;Hello&amp;#x27;),
&amp;#x27; &amp;#x27;,
React.createElement(&amp;#x27;span&amp;#x27;, null, &amp;#x27;World&amp;#x27;),
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;What you get back from a &lt;code&gt;React.createElement&lt;/code&gt; call is actually a simple object:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;// &amp;lt;div id=&amp;quot;root&amp;quot;&amp;gt;Hello world&amp;lt;/div&amp;gt;
{
type: &amp;quot;div&amp;quot;,
key: null,
ref: null,
props: { id: &amp;quot;root&amp;quot;, children: &amp;quot;Hello world&amp;quot; },
_owner: null,
_store: {}
};
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When you pass an object like that to &lt;code&gt;ReactDOM.render&lt;/code&gt; or any other renderer,
it&amp;#x27;s the renderer&amp;#x27;s job to interpret that element object and create DOM nodes or
whatever else out of it. Neat right?!&lt;/p&gt;&lt;p&gt;Here are a few more examples for you:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;ui = &amp;lt;div&amp;gt;Hello {subject}&amp;lt;/div&amp;gt;
ui = React.createElement(&amp;#x27;div&amp;#x27;, null, &amp;#x27;Hello &amp;#x27;, subject)
ui = (
&amp;lt;div&amp;gt;
{greeting} {subject}
&amp;lt;/div&amp;gt;
)
ui = React.createElement(&amp;#x27;div&amp;#x27;, null, greeting, &amp;#x27; &amp;#x27;, subject)
ui = &amp;lt;button onClick={() =&amp;gt; {}}&amp;gt;click me&amp;lt;/button&amp;gt;
ui = React.createElement(&amp;#x27;button&amp;#x27;, {onClick: () =&amp;gt; {}}, &amp;#x27;click me&amp;#x27;)
ui = &amp;lt;div&amp;gt;{error ? &amp;lt;span&amp;gt;{error}&amp;lt;/span&amp;gt; : &amp;lt;span&amp;gt;good to go&amp;lt;/span&amp;gt;}&amp;lt;/div&amp;gt;
ui = React.createElement(
&amp;#x27;div&amp;#x27;,
null,
error
? React.createElement(&amp;#x27;span&amp;#x27;, null, error)
: React.createElement(&amp;#x27;span&amp;#x27;, null, &amp;#x27;good to go&amp;#x27;),
)
ui = (
&amp;lt;div&amp;gt;
{items.map(i =&amp;gt; (
&amp;lt;span key={i.id}&amp;gt;{i.content}&amp;lt;/span&amp;gt;
))}
&amp;lt;/div&amp;gt;
)
ui = React.createElement(
&amp;#x27;div&amp;#x27;,
null,
items.map(i =&amp;gt; React.createElement(&amp;#x27;span&amp;#x27;, {key: i.id}, i.content)),
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Notice that whatever you put inside &lt;code&gt;{&lt;/code&gt; and &lt;code&gt;}&lt;/code&gt; is left alone. This is called an
interpolation and allows you to dynamically inject variables into the values of
props and children. Because of the way this works, the contents of an
interpolation must be JavaScript expressions because they&amp;#x27;re essentially the
right hand of an object assignment or used as an argument to a function call.&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;If you&amp;#x27;d like to play around with this some more, you can try online with
Babel&amp;#x27;s online REPL.
&lt;a href="http://babeljs.io/repl/#?babili=false&amp;amp;browsers=&amp;amp;build=&amp;amp;builtIns=false&amp;amp;spec=false&amp;amp;loose=false&amp;amp;code_lz=DwEwlgbgfAEgpgGwQewAQHdkCcEmAenGgG4g&amp;amp;debug=false&amp;amp;forceAllTransforms=false&amp;amp;shippedProposals=false&amp;amp;circleciRepo=&amp;amp;evaluate=true&amp;amp;fileSize=false&amp;amp;sourceType=module&amp;amp;lineWrap=false&amp;amp;presets=react%2Cstage-2&amp;amp;prettier=true&amp;amp;targets=&amp;amp;version=6.26.0&amp;amp;envVersion=1.6.2"&gt;Start here&lt;/a&gt;.
Hopefully this helps you understand a little more about how JSX works and how
you can use it more effectively. Good luck!&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Learn more about React from me&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://kcd.im/beginner-react"&gt;The Beginner&amp;#x27;s Guide to React&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://kcd.im/advanced-react"&gt;Advanced React Component Patterns&lt;/a&gt; (also on
&lt;a href="https://frontendmasters.com/courses/advanced-react-patterns"&gt;Frontend Masters&lt;/a&gt;).&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://medium.com/merrickchristensen/headless-user-interface-components-565b0c0f2e18"&gt;&amp;quot;Headless User Interface Components&lt;/a&gt; — &amp;quot;A
headless user interface component is a component that offers maximum visual
flexibility by providing no interface. &amp;quot;Wait for a second, are you advocating
a user interface pattern that doesn&amp;#x27;t have a user interface?&amp;quot; Yes. That is
exactly what I&amp;#x27;m advocating.&amp;quot; Brilliant article by my friend
&lt;a href="https://twitter.com/iammerrick"&gt;Merrick Christensen&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/jackfranklin/vscode-go-to-file"&gt;vscode-go-to-file&lt;/a&gt; — A
plugin that aims to replicate some of Vim&amp;#x27;s &amp;quot;go to file&amp;quot; (&lt;code&gt;gf&lt;/code&gt;) functionality
by the great &lt;a href="https://twitter.com/Jack_Franklin"&gt;Jack Franklin&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://tabb-extension.com"&gt;tabb&lt;/a&gt; — A Chrome extension to search, save, and
manage your tabs, history, and bookmarks written in
&lt;a href="https://reasonml.github.io"&gt;Reason&lt;/a&gt; by my friend
&lt;a href="https://twitter.com/ethangodt"&gt;Ethan Godt&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/pichillilorenzo/deps-report"&gt;deps-report&lt;/a&gt; — Generate
reports about dependencies and dependents of your JavaScript/TypeScript files
through an AST. It supports import and require statements. By the insightful
&lt;a href="https://twitter.com/LorenzoPichilli"&gt;Lorenzo Pichilli&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/what-is-jsx"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Test Isolation with React]]></title>
<description><![CDATA[Read to the end, I've got some cool things in the "things not to miss"
section The inspiration for this newsletter comes from seeing React tests that look like
this: So I want to talk about the importance of test isolation and guide you to a
better…]]></description>
<link>https://kentcdodds.com/blog/test-isolation-with-react</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/test-isolation-with-react</guid>
<pubDate>Mon, 02 Jul 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;&lt;strong&gt;Read to the end, I&amp;#x27;ve got some cool things in the &amp;quot;things not to miss&amp;quot;
section&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;The inspiration for this newsletter comes from seeing React tests that look like
this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;const utils = render(&amp;lt;Foo /&amp;gt;)
test(&amp;#x27;test 1&amp;#x27;, () =&amp;gt; {
// use utils here
})
test(&amp;#x27;test 2&amp;#x27;, () =&amp;gt; {
// use utils here too
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So I want to talk about the importance of test isolation and guide you to a
better way to write your tests to improve the reliability of the tests, simplify
the code, and increase the confidence your tests and provide as well.&lt;/p&gt;&lt;p&gt;Let&amp;#x27;s take this simple component as an example:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;import React from &amp;#x27;react&amp;#x27;
class Counter extends React.Component {
static defaultProps = {
initialCount: 0,
maxClicks: 3,
}
initialState = {count: this.props.initialCount}
state = this.initialState
handleReset = () =&amp;gt; this.setState(this.initialState)
handleClick = () =&amp;gt;
this.setState(({count}) =&amp;gt;
this.clicksAreTooMany(count) ? null : {count: count + 1},
)
clicksAreTooMany(count) {
return count &amp;gt;= this.props.maxClicks
}
render() {
const {count} = this.state
const tooMany = this.clicksAreTooMany(count)
return (
&amp;lt;div&amp;gt;
&amp;lt;button onClick={this.handleClick} disabled={tooMany}&amp;gt;
Count: {count}
&amp;lt;/button&amp;gt;
{tooMany ? &amp;lt;button onClick={this.handleReset}&amp;gt;reset&amp;lt;/button&amp;gt; : null}
&amp;lt;/div&amp;gt;
)
}
}
export {Counter}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here&amp;#x27;s a rendered version of the component:&lt;/p&gt;&lt;p&gt;&lt;img src="https://kentcdodds.com/0-b5f55287cae6bb4380b4511fb892e6bb.gif" alt="a rendered version of the component"/&gt;&lt;/p&gt;&lt;h3&gt;Our first test suite&lt;/h3&gt;&lt;p&gt;Let&amp;#x27;s start with a test suite like the one that inspired this newsletter:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;import &amp;#x27;jest-dom/extend-expect&amp;#x27; // gives us the toHaveTextContent/toHaveAttribute matchers
import React from &amp;#x27;react&amp;#x27;
import {renderIntoDocument, cleanup, fireEvent} from &amp;#x27;react-testing-library&amp;#x27;
import {Counter} from &amp;#x27;../counter&amp;#x27;
const {getByText} = renderIntoDocument(
&amp;lt;Counter maxClicks={4} initialCount={3} /&amp;gt;,
)
const counterButton = getByText(/^count/i)
afterAll(cleanup) // when all tests are finished, unmount the component
test(&amp;#x27;the counter is initialized to the initialCount&amp;#x27;, () =&amp;gt; {
expect(counterButton).toHaveTextContent(/3)
})
test(&amp;#x27;when clicked, the counter increments the click&amp;#x27;, () =&amp;gt; {
fireEvent.click(counterButton)
expect(counterButton).toHaveTextContent(/4)
})
test(`the counter button is disabled when it&amp;#x27;s hit the maxClicks`, () =&amp;gt; {
fireEvent.click(counterButton)
expect(counterButton).toHaveAttribute(&amp;#x27;disabled&amp;#x27;)
})
test(`the counter button does not increment the count when clicked when it&amp;#x27;s hit the maxClicks`, () =&amp;gt; {
expect(counterButton).toHaveTextContent(/4)
})
test(`the reset button has been rendered and resets the count when it&amp;#x27;s hit the maxClicks`, () =&amp;gt; {
fireEvent.click(getByText(/reset/i))
expect(counterButton).toHaveTextContent(/3)
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;These tests give us 100% coverage of the component and verify exactly what they
say they&amp;#x27;ll verify. The problem is that they share mutable state. What is the
mutable state they&amp;#x27;re sharing? The component! One test clicks the counter button
and the other tests rely on that fact to pass. If we were to delete (or &lt;code&gt;.skip&lt;/code&gt;)
the test called &amp;quot;when clicked, the counter increments the click&amp;quot; it would break
all the following tests:&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:800px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/110439ee0087a10f5ff10ccedc2476c4/8ff1e/1.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:141.125%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="broken tests" title="broken tests" src="https://kentcdodds.com/static/110439ee0087a10f5ff10ccedc2476c4/8ff1e/1.png" srcSet="https://kentcdodds.com/static/110439ee0087a10f5ff10ccedc2476c4/f4a45/1.png 259w,https://kentcdodds.com/static/110439ee0087a10f5ff10ccedc2476c4/ef0f6/1.png 518w,https://kentcdodds.com/static/110439ee0087a10f5ff10ccedc2476c4/8ff1e/1.png 800w" sizes="(max-width: 800px) 100vw, 800px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;This is a problem because it means that we can&amp;#x27;t reliably refactor these tests,
or run a single test in isolation of the others for debugging purposes because
we don&amp;#x27;t know which tests are impacting the functionality of others. It can be
really confusing when someone comes in to make changes to one test and other
tests start breaking out of nowhere.&lt;/p&gt;&lt;h3&gt;Better&lt;/h3&gt;&lt;p&gt;So let&amp;#x27;s try something else and see how that changes things:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;import &amp;#x27;jest-dom/extend-expect&amp;#x27;
import React from &amp;#x27;react&amp;#x27;
import {renderIntoDocument, cleanup, fireEvent} from &amp;#x27;react-testing-library&amp;#x27;
import {Counter} from &amp;#x27;../counter&amp;#x27;
let getByText, counterButton
beforeEach(() =&amp;gt; {
const utils = renderIntoDocument(&amp;lt;Counter maxClicks={4} initialCount={3} /&amp;gt;)
getByText = utils.getByText
counterButton = utils.getByText(/^count/i)
})
afterEach(cleanup)
test(&amp;#x27;the counter is initialized to the initialCount&amp;#x27;, () =&amp;gt; {
expect(counterButton).toHaveTextContent(/3)
})
test(&amp;#x27;when clicked, the counter increments the click&amp;#x27;, () =&amp;gt; {
fireEvent.click(counterButton)
expect(counterButton).toHaveTextContent(/4)
})
test(`the counter button is disabled when it&amp;#x27;s hit the maxClicks`, () =&amp;gt; {
fireEvent.click(counterButton)
expect(counterButton).toHaveAttribute(&amp;#x27;disabled&amp;#x27;)
})
test(`the counter button does not increment the count when clicked when it&amp;#x27;s hit the maxClicks`, () =&amp;gt; {
fireEvent.click(counterButton)
fireEvent.click(counterButton)
expect(counterButton).toHaveTextContent(/4)
})
test(`the reset button has been rendered and resets the count when it&amp;#x27;s hit the maxClicks`, () =&amp;gt; {
fireEvent.click(counterButton)
fireEvent.click(getByText(/reset/i))
expect(counterButton).toHaveTextContent(/3)
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With this, each test is completely isolated from the other. We can delete or
skip any test and the rest of the tests continue to pass. The biggest
fundamental difference here is that each test has its own count instance to work
with and it&amp;#x27;s unmounted after each test (&lt;code&gt;afterEach(cleanup)&lt;/code&gt;). This
significantly reduces the amount of complexity of our tests with minor changes.&lt;/p&gt;&lt;p&gt;One thing people often say against this approach is that it&amp;#x27;s slower than the
previous approach. I&amp;#x27;m not totally sure how to respond to that... Like, how much
slower? Like a few milliseconds? In that case, so what? A few seconds? Then your
component should probably be optimized because that&amp;#x27;s just terrible. I know it
adds up over time, but with the added confidence and improved maintainability of
this approach, I&amp;#x27;d gladly wait an extra few seconds to render things this way.
In addition, you shouldn&amp;#x27;t often have to run the entire test base anyway thanks
to great watch mode support like we have in Jest.&lt;/p&gt;&lt;h3&gt;Even better&lt;/h3&gt;&lt;p&gt;So I&amp;#x27;m actually still not super happy with the tests we have above. I&amp;#x27;m not a
huge fan of &lt;code&gt;beforeEach&lt;/code&gt; and sharing variables between tests.
&lt;a href="https://www.briefs.fm/3-minutes-with-kent/27"&gt;I feel like they lead to tests that are harder to understand&lt;/a&gt;.
Let&amp;#x27;s try again:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;import &amp;#x27;jest-dom/extend-expect&amp;#x27;
import React from &amp;#x27;react&amp;#x27;
import {renderIntoDocument, cleanup, fireEvent} from &amp;#x27;react-testing-library&amp;#x27;
import {Counter} from &amp;#x27;../counter&amp;#x27;
afterEach(cleanup)
function renderCounter(props) {
const utils = renderIntoDocument(
&amp;lt;Counter maxClicks={4} initialCount={3} {...props} /&amp;gt;,
)
const counterButton = utils.getByText(/^count/i)
return {...utils, counterButton}
}
test(&amp;#x27;the counter is initialized to the initialCount&amp;#x27;, () =&amp;gt; {
const {counterButton} = renderCounter()
expect(counterButton).toHaveTextContent(/3)
})
test(&amp;#x27;when clicked, the counter increments the click&amp;#x27;, () =&amp;gt; {
const {counterButton} = renderCounter()
fireEvent.click(counterButton)
expect(counterButton).toHaveTextContent(/4)
})
test(`the counter button is disabled when it&amp;#x27;s hit the maxClicks`, () =&amp;gt; {
const {counterButton} = renderCounter({
maxClicks: 4,
initialCount: 4,
})
expect(counterButton).toHaveAttribute(&amp;#x27;disabled&amp;#x27;)
})
test(`the counter button does not increment the count when clicked when it&amp;#x27;s hit the maxClicks`, () =&amp;gt; {
const {counterButton} = renderCounter({
maxClicks: 4,
initialCount: 4,
})
fireEvent.click(counterButton)
expect(counterButton).toHaveTextContent(/4)
})
test(`the reset button has been rendered and resets the count when it&amp;#x27;s hit the maxClicks`, () =&amp;gt; {
const {getByText, counterButton} = renderCounter()
fireEvent.click(counterButton)
fireEvent.click(getByText(/reset/i))
expect(counterButton).toHaveTextContent(/3)
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here we&amp;#x27;ve increased some boilerplate, but now every test is not only isolated
technically, but also visually. You can look at a test and see exactly what it
does without having to worry about what hooks are happening within the test.
This is a big win in the ability for you to be able to refactor, remove, or add
to the tests.&lt;/p&gt;&lt;h3&gt;Even better better&lt;/h3&gt;&lt;p&gt;I like what we have now, but I think we need to take things one step further
before I feel really happy about things. We&amp;#x27;ve split our tests up by
functionality, but what we really want to have confidence in is the use case
that our component satisfies. It allows clicks until the maxClicks is reached,
then requires a reset. That&amp;#x27;s what we&amp;#x27;re trying to verify and gain confidence
in. I&amp;#x27;m much more interested in use cases when I&amp;#x27;m testing than specific
functionality. So what would these tests look like if we concerned ourselves
more with the use case than the individual functionality?&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;import &amp;#x27;jest-dom/extend-expect&amp;#x27;
import React from &amp;#x27;react&amp;#x27;
import {renderIntoDocument, cleanup, fireEvent} from &amp;#x27;react-testing-library&amp;#x27;
import {Counter} from &amp;#x27;../counter&amp;#x27;
afterEach(cleanup)
test(&amp;#x27;allows clicks until the maxClicks is reached, then requires a reset&amp;#x27;, () =&amp;gt; {
const {getByText} = renderIntoDocument(
&amp;lt;Counter maxClicks={4} initialCount={3} /&amp;gt;,
)
const counterButton = getByText(/^count/i)
// the counter is initialized to the initialCount
expect(counterButton).toHaveTextContent(/3)
// when clicked, the counter increments the click
fireEvent.click(counterButton)
expect(counterButton).toHaveTextContent(/4)
// the counter button is disabled when it&amp;#x27;s hit the maxClicks
expect(counterButton).toHaveAttribute(&amp;#x27;disabled&amp;#x27;)
// the counter button no longer increments the count when clicked.
fireEvent.click(counterButton)
expect(counterButton).toHaveTextContent(/4)
// the reset button has been rendered and is clickable
fireEvent.click(getByText(/reset/i))
// the counter is reset to the initialCount
expect(counterButton).toHaveTextContent(/3)
// the counter can be clicked and increment the count again
fireEvent.click(counterButton)
expect(counterButton).toHaveTextContent(/4)
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I really love this kind of test. It helps me avoid thinking about functionality
and focus more on what I&amp;#x27;m trying to accomplish with the component. It serves as
much better documentation of the component than the other tests as well.&lt;/p&gt;&lt;p&gt;In the past, the reason we wouldn&amp;#x27;t do this (have multiple assertions in a
single test) is because it was hard to tell which part of the test broke. But
now we have much better error output and it&amp;#x27;s really easy to identify what part
of the test broke. For example:&lt;/p&gt;&lt;p&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:800px"&gt;
&lt;a class="gatsby-resp-image-link" href="https://kentcdodds.com/static/8ad6d8b27848cd42899f8ac068f9f195/8ff1e/2.png" style="display:block" target="_blank" rel="noopener"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:57.50000000000001%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="broken tests" title="broken tests" src="https://kentcdodds.com/static/8ad6d8b27848cd42899f8ac068f9f195/8ff1e/2.png" srcSet="https://kentcdodds.com/static/8ad6d8b27848cd42899f8ac068f9f195/f4a45/2.png 259w,https://kentcdodds.com/static/8ad6d8b27848cd42899f8ac068f9f195/ef0f6/2.png 518w,https://kentcdodds.com/static/8ad6d8b27848cd42899f8ac068f9f195/8ff1e/2.png 800w" sizes="(max-width: 800px) 100vw, 800px"/&gt;
&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;The code frame is especially helpful. It shows not only the line number, but the
code around the failed assertion which shows our comments and other code to
really help give us context around the error message that not even our previous
tests gave us.&lt;/p&gt;&lt;p&gt;I should mention, this isn&amp;#x27;t to say that you shouldn&amp;#x27;t separate test cases for a
component! There are many reasons you&amp;#x27;d want to do that and most of the time you
will. Just focus more on use cases than functionality and you&amp;#x27;ll generally cover
most of the code you care about with that. Then you can have a few extra tests
to handle edge cases.&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;I hope this is helpful to you! You can find the code for this example
&lt;a href="https://github.com/kentcdodds/react-test-isolation"&gt;here&lt;/a&gt;. Try to keep your
tests isolated from one another and focus on use cases rather than functionality
and you&amp;#x27;ll have a much better time testing! Good luck!&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Learn more about testing from me&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://frontendmasters.com"&gt;Frontend Masters&lt;/a&gt;:
&lt;a href="https://frontendmasters.com/workshops/testing-practices-principles"&gt;Testing Practices and Principles&lt;/a&gt;,
&lt;a href="https://frontendmasters.com/courses/testing-react"&gt;Testing React Applications&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://egghead.io/lessons/react-confidently-ship-production-react-apps"&gt;Confidently Ship Production React Apps&lt;/a&gt; — Something
new on &lt;a href="http://egghead.io"&gt;egghead.io&lt;/a&gt;. It&amp;#x27;s a recording of one of my talks
especially for &lt;a href="http://egghead.io"&gt;egghead.io&lt;/a&gt;. I think you&amp;#x27;ll really enjoy it
(and it&amp;#x27;s 🆓)&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/Fha2bVoC8SE?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;Write tests. Not too many. Mostly integration.&lt;/a&gt; — My
talk at Assert.js conference
(&lt;a href="http://kcd.im/write-tests"&gt;and here&amp;#x27;s the blog post&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/VQZx1Z3sW0E?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;Testing Practices and Principles&lt;/a&gt; — A
recording of my workshop at Assert.js&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://medium.com/byteconf/byteconf-react-speakers-round-one-ab25af8edf23"&gt;Byteconf React Speakers: Round One&lt;/a&gt; — Look!
It&amp;#x27;s a free online conference and I&amp;#x27;m speaking at it!&lt;/li&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/blog/downshift-2-0-0-released"&gt;🏎 downshift 2.0.0 released 🎉&lt;/a&gt; — Even better
accessibility, React Native and ReasonReact support, even simpler API,
improved docs, new examples site, Flow and TypeScript support, and a new
online community ⚛️&lt;/li&gt;&lt;li&gt;&lt;a href="http://keycode.info"&gt;keycode.info&lt;/a&gt; by
&lt;a href="https://twitter.com/wesbos"&gt;Wes Bos&lt;/a&gt; — shows you the javascript character
code for the key you type. Handy!&lt;/li&gt;&lt;li&gt;&lt;a href="https://store.google.com/us/product/google_pixelbook"&gt;Chrome Pixelbook&lt;/a&gt; — It&amp;#x27;s
what I&amp;#x27;m using to write this right now and it&amp;#x27;s pretty slick!&lt;/li&gt;&lt;li&gt;&lt;a href="https://medium.com/@Daajust/testing-socket-io-client-app-using-jest-and-react-testing-library-9cae93c070a3"&gt;Testing Socket.io-client app using Jest and react-testing-library&lt;/a&gt;
by my friend &lt;a href="https://twitter.com/Daajust"&gt;Justice Mba&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;a href="https://medium.com/@hemal7735/webpack-4-splitchunks-plugin-d9fbbe091fd0"&gt;Webpack 4 — Mysterious SplitChunks Plugin&lt;/a&gt; — My
fellow PayPal engineer &lt;a href="https://twitter.com/TheHemalPatel"&gt;Hemal Patel&lt;/a&gt; wrote
about how the &lt;code&gt;splitChunks.chunks&lt;/code&gt; feature works. Pretty interesting!&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/test-isolation-with-react"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[JavaScript default parameters]]></title>
<description><![CDATA[Today I thought I'd take you through one of the examples from
my es6 workshop . Consider the following code: It's fairly simple, but there are potential bugs (read about
Falsy
on MDN ) and some
annoying boilerplate. Luckily for us, ES6 introduced…]]></description>
<link>https://kentcdodds.com/blog/javascript-default-parameters</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/javascript-default-parameters</guid>
<pubDate>Mon, 25 Jun 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;Today I thought I&amp;#x27;d take you through one of the examples from
&lt;a href="https://github.com/kentcdodds/es6-workshop"&gt;my es6 workshop&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Consider the following code:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;function getCandy(kind, size, upperKind, callback) {
if (!kind) {
requiredParam(&amp;#x27;kind&amp;#x27;)
}
if (!size) {
requiredParam(&amp;#x27;size&amp;#x27;)
}
upperKind = upperKind || kind.toUpperCase()
callback = callback || function noop() {}
const result = {kind, size, upperKind}
callback(result)
return result
}
function requiredParam(argName) {
throw new Error(`${argName} is required`)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It&amp;#x27;s fairly simple, but there are potential bugs (read about
&lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Falsy"&gt;&lt;code&gt;Falsy&lt;/code&gt;&lt;/a&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Falsy"&gt;on MDN&lt;/a&gt;) and some
annoying boilerplate. Luckily for us, ES6 introduced new syntax into JavaScript
that we can use to simplify things a bit. In particular:
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters"&gt;default parameters&lt;/a&gt;.
Let&amp;#x27;s checkout what the above would be like when using this feature.&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;function getCandy(
kind = requiredParam(&amp;#x27;kind&amp;#x27;),
size = requiredParam(&amp;#x27;size&amp;#x27;),
upperKind = kind.toUpperCase(),
callback = function noop() {},
) {
const result = {kind, size, upperKind}
callback(result)
return result
}
function requiredParam(argName) {
throw new Error(`${argName} is required`)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Notice that we&amp;#x27;re able to take each expression and put it on the right side of
the equals sign. If the parameter is &lt;code&gt;undefined&lt;/code&gt;then the expression on the right
side will be evaluated. This allows us to only call the &lt;code&gt;requiredParam&lt;/code&gt; function
if &lt;code&gt;kind&lt;/code&gt; or &lt;code&gt;size&lt;/code&gt; is &lt;code&gt;undefined&lt;/code&gt;. It also is possible to use the value of
other parameters in our expression like we do in the default param for
&lt;code&gt;upperKind&lt;/code&gt; which I find to be a ridiculously cool feature and I use this all
the time in options configuration for some of my tools
(&lt;a href="https://github.com/babel-utils/babel-plugin-tester/blob/4b512e895a8934cdc6bb54be3be3241d56cfb9dc/src/index.js#L25-L28"&gt;for example&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;I&amp;#x27;ll add that the same kinds of semantics would apply for object destructuring
(whether as a parameter or not) as well. For example, if we change the arguments
to be an options object:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;function getCandy(options = {}) {
const {
kind = requiredParam(&amp;#x27;kind&amp;#x27;),
size = requiredParam(&amp;#x27;size&amp;#x27;),
upperKind = kind.toUpperCase(),
callback = function noop() {},
} = options
// etc...
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Or, if we want to destructure the options object directly in the parameter list:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;function getCandy({
kind = requiredParam(&amp;#x27;kind&amp;#x27;),
size = requiredParam(&amp;#x27;size&amp;#x27;),
upperKind = kind.toUpperCase(),
callback = function noop() {},
} = {}) {
// etc...
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Fun stuff!&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;I hope you find this helpful! If you&amp;#x27;d like to watch me talk about this a bit,
you can check out this section of my ES6 workshop I gave and recorded at PayPal
a while back:
&lt;a href="https://youtu.be/t3R3R7UyN2Y"&gt;ES6 and Beyond Workshop Part 1 at PayPal (Jan 2017)&lt;/a&gt;.
Good luck!&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Learn more about JavaScript from me&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://youtu.be/kTlcu16rSLc?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;More than you want to know about ES6 Modules @ Learn to Code Websites and Apps Meetup (remote)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/t3R3R7UyN2Y?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;ES6 and Beyond Workshop Part 1 at PayPal (Jan 2017)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/eOKQDh50ECU?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;ES6 and Beyond Workshop Part 2 at PayPal (March 2017)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/workshops/#code-transformation-and-linting"&gt;Code Transformation and Linting&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://kentcdodds.com/talks/#writing-custom-babel-and-eslint-plugins-with-asts"&gt;Writing custom Babel and ESLint plugins with ASTs&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Also, don&amp;#x27;t forget to subscribe to &lt;a href="http://kcd.im/youtube"&gt;my youtube channel&lt;/a&gt;
for my daily devtips, like
&lt;a href="https://youtu.be/FsgGx1SMXn0?list=PLV5CVI1eNcJgCrPH_e6d57KRUTiDZgs0u"&gt;the one today where&lt;/a&gt;
I demo some advanced features of destructuring!&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://semver-calc.now.sh"&gt;Semver Calc&lt;/a&gt; — A sweet new app by
&lt;a href="https://twitter.com/tarang9211"&gt;Tarang Hirani&lt;/a&gt; and
&lt;a href="https://twitter.com/__shriram"&gt;Shriram Balaji&lt;/a&gt;. It allows you to try out
semver ranges on packages versions to fine-tune the version range. Especially
useful for &lt;code&gt;peerDependencies&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.anxietytech.com"&gt;AnxietyTech&lt;/a&gt; — A conference on July 18th, 2018
to bring awareness of mental health issues in tech. Use code &lt;code&gt;TECH&lt;/code&gt; for \$25
off.&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/sindresorhus/refined-twitter"&gt;Refined Twitter&lt;/a&gt; — Browser
extension that simplifies the Twitter interface and adds useful features. I
love it.&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/javascript-default-parameters"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Dealing with FOMO]]></title>
<description><![CDATA[🚨 Announcements 🚨 Advanced React Online and
Live! Join me in my online workshop this week! Get your questions answered in
real-time and have time to work through exercises to up your React game. DevTips with Kent  — I'm taking a break this week…]]></description>
<link>https://kentcdodds.com/blog/dealing-with-fomo</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/dealing-with-fomo</guid>
<pubDate>Mon, 18 Jun 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;🚨 &lt;strong&gt;Announcements&lt;/strong&gt; 🚨&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://workshop.me/2018-06-advanced-react?a=kent"&gt;Advanced React Online&lt;/a&gt; and
Live! Join me in my online workshop this week! Get your questions answered in
real-time and have time to work through exercises to up your React game.&lt;/li&gt;&lt;li&gt;&lt;a href="http://kcd.im/devtips"&gt;DevTips with Kent&lt;/a&gt; — I&amp;#x27;m taking a break this week
because I&amp;#x27;m on vacation with my family. Feel free to enjoy the recordings
until I get back next week!&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If you&amp;#x27;re not familiar with the acronym FOMO that&amp;#x27;s totally fine (and also a
tiny bit ironic). FOMO stands for &amp;quot;Fear Of Missing Out.&amp;quot; You might feel this for
example if you&amp;#x27;re deciding whether to learn
&lt;a href="https://reasonml.github.io"&gt;ReasonML&lt;/a&gt; or keep going deep into JavaScript (this
happens to be something that I&amp;#x27;m currently struggling with).&lt;/p&gt;&lt;h3&gt;What&amp;#x27;s wrong with FOMO&lt;/h3&gt;&lt;p&gt;FOMO is paralyzing. I once entered a conversation with a man at a conference who
was very concerned about which JavaScript framework to use for building
applications. He asked me how I could possibly decide. I just said that I tried
a few and chose one that I thought was pretty good and went with it.&lt;/p&gt;&lt;p&gt;He couldn&amp;#x27;t grasp it at all and showed me a Google Spreadsheet he&amp;#x27;d created that
would probably take half a tree to print (a small tree probably). It had columns
for every framework imaginable and rows for every conceivable feature. I&amp;#x27;m
telling you, this thing was HUGE.&lt;/p&gt;&lt;p&gt;Even with this exhaustive comparison, he still couldn&amp;#x27;t decide. He was worried
about making the wrong decision. We call this analysis paralysis and I actually
mentioned to him that I thought he&amp;#x27;d hit that point which he denied. Whether or
not that really was the case, he was emotionally consumed by this decision.&lt;/p&gt;&lt;h3&gt;Where does FOMO come from?&lt;/h3&gt;&lt;p&gt;FOMO is entirely based on comparing one&amp;#x27;s self with others. These kinds of
comparisons are entirely unhealthy and insatiable. No matter how much knowledge
or experience you gain, there will always be someone who has more and you will
be left feeling inadequate.&lt;/p&gt;&lt;p&gt;The reason for this is we often make the mistake of thinking there are only two
people in the world: You, and everyone else. While this entirely false, it&amp;#x27;s an
easy pit to fall into and leads to FOMO and feelings that we can never measure
up to where everyone who is not us is at.&lt;/p&gt;&lt;h3&gt;How to manage&lt;/h3&gt;&lt;p&gt;Knowing that FOMO comes from the unhealthy tendency to compare ourselves to
others, managing and gaining control of FOMO becomes a task of controlling that
tendency. I&amp;#x27;m still working on this myself, but I think a great first step is to
be mindful of yourself and the thoughts you&amp;#x27;re having about others and yourself.
Try to catch yourself thinking thoughts like: &amp;quot;I&amp;#x27;m better than them at x&amp;quot; or
&amp;quot;Wow, I&amp;#x27;ll never be that good at x as they are.&amp;quot; However true those thoughts
are, they are not helpful or compassionate to yourself or others.&lt;/p&gt;&lt;p&gt;Instead, consciously train your brain to think things like: &amp;quot;How can I help
others learn what I know?&amp;quot; or &amp;quot;Wow! That&amp;#x27;s really cool that they&amp;#x27;re so talented
at that!&amp;quot; There&amp;#x27;s nothing wrong with a healthy desire to learn more, and you can
train your brain to think positively about your ability to improve. Changing the
tone and attitude of your own self-talk can really make a positive impact of how
you feel about yourself and others. You&amp;#x27;ll feel more motivated to improve and
feel empowered to do so.&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;I think it&amp;#x27;s really important for you to know that your brain is a muscle and
you can exercise different parts of it. Try to exercise the parts of your brain
that help you be more compassionate to yourself and others and you&amp;#x27;ll reduce
your unhealthy FOMO and develop a healthy amount of MTBB (Motivation To Become
Better... I just made that up).&lt;/p&gt;&lt;p&gt;I hope that&amp;#x27;s helpful to you. Like I said, this is something I&amp;#x27;m actively
working on in myself, I hope that together we can work on improving this aspect
of ourselves and find more happiness in life :) Good luck!&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://kcd.im/advanced-react"&gt;&lt;strong&gt;UPDATED&lt;/strong&gt;: Advanced React Component Patterns&lt;/a&gt; — This
is the &lt;a href="http://egghead.io"&gt;egghead.io&lt;/a&gt; version of my course material
completely updated for the latest in React with &lt;strong&gt;NEW PATTERNS&lt;/strong&gt; (like
&lt;a href="https://kentcdodds.com/blog/the-state-reducer-pattern"&gt;the state reducer prop pattern&lt;/a&gt;). Enjoy!&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/vVlcq3e1ooI"&gt;Drive with Kent — Tech phone call recording&lt;/a&gt; — In
case you missed it,
&lt;a href="https://github.com/kentcdodds/ama/issues/405"&gt;I took a 6 hour drive&lt;/a&gt; and had
a phone conversation with people about React, Testing, CSS-in-JS, and more.
Check it out!&lt;/li&gt;&lt;li&gt;&lt;a href="https://reach.tech/router"&gt;reach-router&lt;/a&gt; — Not a typo, this is a new router
from &lt;a href="https://twitter.com/ryanflorence"&gt;Ryan Florence&lt;/a&gt; (creator of
react-router and many others). It&amp;#x27;s pretty neat and has great docs. I did
&lt;a href="https://youtu.be/J1vsBrSUptA?list=PLV5CVI1eNcJgCrPH_e6d57KRUTiDZgs0u"&gt;a devtip&lt;/a&gt;
with it the other day.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.richardkotze.com/coding/react-testing-library-jest"&gt;react-testing-library &amp;amp; Jest&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/dealing-with-fomo"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[🏎 downshift 2.0.0 released 🎉]]></title>
<description><![CDATA[Even better accessibility, React Native and ReasonReact support, even simpler
API, improved docs, new examples site, Flow and TypeScript support, and a new
online community ⚛️ I'm excited to let the world know that downshift 2.0.0 has been released…]]></description>
<link>https://kentcdodds.com/blog/downshift-2-0-0-released</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/downshift-2-0-0-released</guid>
<pubDate>Fri, 15 Jun 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;&lt;em&gt;Even better accessibility, React Native and ReasonReact support, even simpler
API, improved docs, new examples site, Flow and TypeScript support, and a new
online community ⚛️&lt;/em&gt;&lt;/p&gt;&lt;p&gt;I&amp;#x27;m excited to let the world know that downshift 2.0.0 has been released! So I&amp;#x27;m
going to do it now:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Hey world! downshift 2.0.0 has been released!&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Woo! So what do you have to look forward to? Let&amp;#x27;s dive in! (If you haven&amp;#x27;t
heard of downshift, consider reading
&lt;a href="https://kentcdodds.com/blog/introducing-downshift-for-react"&gt;the original release post&lt;/a&gt;).&lt;/p&gt;&lt;h3&gt;Improved Accessibility (&lt;a href="https://twitter.com/hashtag/a11y"&gt;&lt;strong&gt;#a11y&lt;/strong&gt;&lt;/a&gt;)&lt;/h3&gt;&lt;p&gt;Lead primarily by &lt;a href="https://github.com/cycomachead"&gt;Michael Ball&lt;/a&gt; (with helpful
reviews from several others), we
&lt;a href="https://github.com/downshift-js/downshift/pull/285"&gt;received&lt;/a&gt; a number of
improvements to the accessibility features baked-into downshift. He also added a
new
&lt;a href="https://github.com/downshift-js/downshift/blob/master/README.md#getmenuprops"&gt;&lt;code&gt;getMenuProps&lt;/code&gt;&lt;/a&gt;
&lt;a href="https://kentcdodds.com/blog/how-to-give-rendering-control-to-users-with-prop-getters"&gt;prop getter&lt;/a&gt;
(which was also instrumental in fixing
&lt;a href="https://github.com/downshift-js/downshift/issues/287"&gt;a bug with React Portals&lt;/a&gt;).
This allows us to add some &lt;code&gt;aria-&lt;/code&gt; attributes to the menu you render that will
help assistive technologies use your enhanced input components! Woo! I&amp;#x27;ve also
updated many of the examples to use more semantically correct elements.&lt;/p&gt;&lt;h3&gt;React Native Support&lt;/h3&gt;&lt;p&gt;We&amp;#x27;ve actually had this for a while in 1.x, but I wanted to include this in the
blog post because there was never really an official announcement and I think
that this is great! This is largely thanks to work by
&lt;a href="https://github.com/eliperkins"&gt;Eli Perkins&lt;/a&gt;! They&amp;#x27;ve already shipped downshift
to production in their iOS app:&lt;/p&gt;&lt;p&gt;&lt;a href="https://github.com/downshift-js/downshift/issues/185#issuecomment-365965566"&gt;&lt;span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:800px"&gt;
&lt;span class="gatsby-resp-image-background-image" style="padding-bottom:93.875%;position:relative;bottom:0px;left:0px;background-size:cover;display:block"&gt;&lt;/span&gt;
&lt;img class="gatsby-resp-image-image" alt="Screenshot of downshift code in React Native from Eli" title="Screenshot of downshift code in React Native from Eli" src="https://kentcdodds.com/static/4276bfc11a9fe5811860d718d994a418/8ff1e/0.png" srcSet="https://kentcdodds.com/static/4276bfc11a9fe5811860d718d994a418/f4a45/0.png 259w,https://kentcdodds.com/static/4276bfc11a9fe5811860d718d994a418/ef0f6/0.png 518w,https://kentcdodds.com/static/4276bfc11a9fe5811860d718d994a418/8ff1e/0.png 800w" sizes="(max-width: 800px) 100vw, 800px"/&gt;
&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;h3&gt;ReasonReact Support&lt;/h3&gt;&lt;p&gt;We&amp;#x27;ve actually had this for a while too, but I want to call it out especially.
Thanks to &lt;a href="https://github.com/emmenko"&gt;Nicola Molinari&lt;/a&gt; there are
&lt;a href="https://github.com/downshift-js/downshift/blob/master/README.md#bindings-for-reasonml"&gt;official Reason bindings for downshift&lt;/a&gt;.
So you can build UIs for any platform you can imagine with downshift and
&lt;a href="https://reasonml.github.io"&gt;ReasonML&lt;/a&gt;. Soooo cool!&lt;/p&gt;&lt;h3&gt;Simpler API&lt;/h3&gt;&lt;p&gt;It&amp;#x27;s generally a good idea to avoid APIs which allow two ways to do the same
thing. It&amp;#x27;s just another thing to list in docs, and you have to help people
understand what the differences are (if there are any).&lt;/p&gt;&lt;p&gt;Up until downshift 2.0.0, we had two props that could be used for your
&lt;a href="https://cdb.reacttraining.com/use-a-render-prop-50de598f11ce"&gt;render prop&lt;/a&gt;:
&lt;code&gt;render&lt;/code&gt; and &lt;code&gt;children&lt;/code&gt;. Then React released the official context API which uses
render props and they called it &lt;code&gt;children&lt;/code&gt;. In an effort to develop consistency
throughout the ecosystem, we&amp;#x27;ve dropped the prop called &lt;code&gt;render&lt;/code&gt; and now only
support &lt;code&gt;children&lt;/code&gt;.&lt;/p&gt;&lt;h3&gt;Improved Docs&lt;/h3&gt;&lt;p&gt;After downshift was out for a while, I started to realize that folks missed out
on some of the more useful and necessary props (like
&lt;a href="https://github.com/downshift-js/downshift/blob/master/README.md#itemtostring"&gt;&lt;code&gt;itemToString&lt;/code&gt;&lt;/a&gt;).
I blame myself for this and recently reorganized the docs to make more relevant
information more apparent.&lt;/p&gt;&lt;h3&gt;New Examples Site&lt;/h3&gt;&lt;p&gt;It&amp;#x27;s just getting started (so there are only a few examples), but it&amp;#x27;s here and
ready for contributions!&lt;/p&gt;&lt;p&gt;Find it and contribute
(&lt;a href="https://hackernoon.com/announcing-codesandbox-2-0-938cff3a0fcb"&gt;right in the browser!&lt;/a&gt;)
on codesandbox!&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Codesandbox:
&lt;a href="https://codesandbox.io/s/github/kentcdodds/downshift-examples"&gt;codesandbox.io/s/github/kentcdodds/downshift-examples&lt;/a&gt;&lt;/li&gt;&lt;li&gt;GitHub:
&lt;a href="https://github.com/kentcdodds/downshift-examples"&gt;https://github.com/kentcdodds/downshift-examples&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;figcaption&gt;The codesandbox for the examples site&lt;/figcaption&gt;&lt;h3&gt;Improved TypeScript Support&lt;/h3&gt;&lt;p&gt;A great effort lead primarily by
&lt;a href="https://github.com/stereobooster"&gt;@stereobooster&lt;/a&gt; has lead to improved
TypeScript definitions for downshift. Even if you don&amp;#x27;t use TypeScript, you&amp;#x27;ll
benefit from these typings as they will help ensure we don&amp;#x27;t publish breaking
changes unknowingly and if you use VSCode you&amp;#x27;ll benefit from these typings with
the built-in Intellisense!&lt;/p&gt;&lt;h3&gt;Support for Flow!&lt;/h3&gt;&lt;p&gt;Another awesome contribution by
&lt;a href="https://github.com/stereobooster"&gt;@stereobooster&lt;/a&gt;. We&amp;#x27;re now generating flow
type definitions from the TypeScript definitions, so if you&amp;#x27;re on the Flow
train, you&amp;#x27;ll get more type-safety when working with downshift!&lt;/p&gt;&lt;h3&gt;We&amp;#x27;re on spectrum!&lt;/h3&gt;&lt;p&gt;&lt;a href="https://spectrum.chat/downshift"&gt;&lt;strong&gt;downshift&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Yeehaw! Join us there to talk about the present and future of downshift and get
help/help others.&lt;/p&gt;&lt;h3&gt;Thanks&lt;/h3&gt;&lt;p&gt;This release and these amazing features would not be possible without help from
all our open source contributors. I&amp;#x27;d like to especially thank these awesome
people:&lt;/p&gt;&lt;p&gt;&lt;a href="https://github.com/stereobooster"&gt;@stereobooster&lt;/a&gt;,
&lt;a href="https://github.com/franklixuefei"&gt;@franklixuefei&lt;/a&gt;,
&lt;a href="https://github.com/dovidweisz"&gt;@dovidweisz&lt;/a&gt;,
&lt;a href="https://github.com/Antontelesh"&gt;@Antontelesh&lt;/a&gt;,
&lt;a href="https://github.com/tansongyang"&gt;@tansongyang&lt;/a&gt;,
&lt;a href="https://github.com/Andarist"&gt;@Andarist&lt;/a&gt;,
&lt;a href="https://github.com/cycomachead"&gt;@cycomachead&lt;/a&gt;,
&lt;a href="https://github.com/mperrotti"&gt;@mperrotti&lt;/a&gt;,
&lt;a href="https://github.com/SiTaggart"&gt;@SiTaggart&lt;/a&gt;, and
&lt;a href="https://github.com/1Copenut"&gt;@1Copenut&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Thank you!&lt;/p&gt;&lt;p&gt;&lt;a href="https://github.com/downshift-js/downshift/releases/tag/v2.0.0"&gt;&lt;em&gt;See the release notes for more info on this release&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/downshift-2-0-0-released"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[When to use Control Props or State Reducers]]></title>
<description><![CDATA[You’ve probably used components or elements that implement the control props
pattern. For example: Read more about the concept of control props in
the react docs . You may not have had much experience with the idea of a
state reducer . In contrast…]]></description>
<link>https://kentcdodds.com/blog/control-props-vs-state-reducers</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/control-props-vs-state-reducers</guid>
<pubDate>Mon, 11 Jun 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;You’ve probably used components or elements that implement the control props
pattern. For example:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;&amp;lt;input value={this.state.inputValue} onChange={this.handleInputChange} /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Read more about the concept of control props in
&lt;a href="https://reactjs.org/docs/forms.html"&gt;the react docs&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;You may not have had much experience with the idea of a
&lt;a href="https://kentcdodds.com/blog/the-state-reducer-pattern"&gt;state reducer&lt;/a&gt;. In contrast to control props,
built-in react elements don’t support state reducers (though I hear that
reason-react does). My library
&lt;a href="https://github.com/downshift-js/downshift"&gt;downshift&lt;/a&gt; supports a state reducer.
Here’s an example of using it to prevent the menu from closing after an item is
selected:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;function stateReducer(state, changes) {
if (changes.type === Downshift.stateChangeTypes.clickItem) {
// when the user clicks an item, prevent
// keep the isOpen to true
return {...changes, isOpen: true}
}
return changes
}
const ui = (
&amp;lt;Downshift stateReducer={stateReducer}&amp;gt;
{() =&amp;gt; &amp;lt;div&amp;gt;{/* some ui stuff */}&amp;lt;/div&amp;gt;}
&amp;lt;/Downshift&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can learn how to implement these patterns from
&lt;a href="https://kentcdodds.com/workshops/#advanced-react-component-patterns"&gt;my Advanced React Component Patterns material&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Both of these patterns help you expose state management to component consumers
and while they have significantly different APIs, they allow much of the same
capabilities. So today I’d like to answer the question I’ve gotten many times
which is: “When should I expose a state reducer or a control prop?”&lt;/p&gt;&lt;p&gt;Control Props are objectively more powerful because they allow complete control
over state from outside the component. Let’s take my favorite Toggle component
as an example:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;class Example extends React.Component {
state = {on: false, inputValue: &amp;#x27;off&amp;#x27;}
handleToggle = on =&amp;gt; {
this.setState({on, inputValue: on ? &amp;#x27;on&amp;#x27; : &amp;#x27;off&amp;#x27;})
}
handleChange = ({target: {value}}) =&amp;gt; {
if (value === &amp;#x27;on&amp;#x27;) {
this.setState({on: true})
} else if (value === &amp;#x27;off&amp;#x27;) {
this.setState({on: false})
}
this.setState({inputValue: value})
}
render() {
const {on} = this.state
return (
&amp;lt;div&amp;gt;
{/*
here we&amp;#x27;re using the `value` control prop
exposed by the &amp;lt;input /&amp;gt; component
*/}
&amp;lt;input value={this.state.inputValue} onChange={this.handleChange} /&amp;gt;
{/*
here we&amp;#x27;re using the `on` control prop
exposed by the &amp;lt;Toggle /&amp;gt; component.
*/}
&amp;lt;Toggle on={on} onToggle={this.handleToggle} /&amp;gt;
&amp;lt;/div&amp;gt;
)
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here’s a rendered version of this component:&lt;/p&gt;&lt;p&gt;&lt;img src="https://kentcdodds.com/toggle1-ae163064b48faf762855da446b06f9b2.gif" alt="gif of the rendered component showing an input and toggle that sync their state"/&gt;&lt;/p&gt;&lt;p&gt;As you can see, I can control the state of the toggle button by changing the
text of the input component, and control the state of the input by clicking on
the toggle. This is powerful because it allows me to have complete control over
the state of these components.&lt;/p&gt;&lt;p&gt;Control props do come with a cost however. They require that the consumer
completely manage state themselves which means the consumer must have a class
component with state and change handlers to update that state.&lt;/p&gt;&lt;p&gt;State reducers do not have to manage the component’s state themselves (though
they can manage some of their own state as needed). Here’s an example of using a
state reducer:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;class Example extends React.Component {
initialState = {timesClicked: 0}
state = this.initialState
handleToggle = (...args) =&amp;gt; {
this.setState(({timesClicked}) =&amp;gt; ({
timesClicked: timesClicked + 1,
}))
}
handleReset = (...args) =&amp;gt; {
this.setState(this.initialState)
}
toggleStateReducer = (state, changes) =&amp;gt; {
if (this.state.timesClicked &amp;gt;= 4) {
return {...changes, on: false}
}
return changes
}
render() {
const {timesClicked} = this.state
return (
&amp;lt;div&amp;gt;
&amp;lt;Toggle
stateReducer={this.toggleStateReducer}
onToggle={this.handleToggle}
onReset={this.handleReset}
/&amp;gt;
{timesClicked &amp;gt; 4 ? (
&amp;lt;div&amp;gt;
Whoa, you clicked too much!
&amp;lt;br /&amp;gt;
&amp;lt;/div&amp;gt;
) : (
&amp;lt;div&amp;gt;Click count: {timesClicked}&amp;lt;/div&amp;gt;
)}
&amp;lt;/div&amp;gt;
)
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And here’s a gif of the rendered interaction.&lt;/p&gt;&lt;p&gt;&lt;img src="https://kentcdodds.com/toggle2-92c108bac456b9786c0be135dd7b811e.gif" alt="gif of the rendered component showing a toggle, reset button, and counter that’s limited to 4 toggles."/&gt;&lt;/p&gt;&lt;p&gt;Now, you could definitely implement this experience using a control prop, but I
would argue that it’s a fair bit simpler if you can use the state reducer. The
biggest limitation of a state reducer is that it’s impossible to set state of
the component from outside it’s normal &lt;code&gt;setState&lt;/code&gt; calls (I couldn&amp;#x27;t implement
the first example using a state reducer).&lt;/p&gt;&lt;p&gt;I hope this is helpful! Feel free to see the implementation and play around with
things in &lt;a href="https://codesandbox.io/s/n09418kvr0"&gt;this codesandbox&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Good luck!&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Learn more about React from me&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://kcd.im/beginner-react"&gt;egghead.io (beginners)&lt;/a&gt; — My Beginner’s Guide
to React absolutely &lt;em&gt;free&lt;/em&gt; on &lt;a href="http://egghead.io"&gt;egghead.io&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;a href="http://kcd.im/advanced-react"&gt;egghead.io (advanced)&lt;/a&gt; — My Advanced React
Component Patterns course available on &lt;a href="http://egghead.io"&gt;egghead.io&lt;/a&gt; today!&lt;/li&gt;&lt;li&gt;&lt;a href="https://frontendmasters.com/workshops/advanced-react-patterns"&gt;Frontend Masters&lt;/a&gt; — My
Advanced React Patterns workshop&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://youtube.com/playlist?list=PLV5CVI1eNcJgCrPH_e6d57KRUTiDZgs0u"&gt;&lt;strong&gt;DevTips with Kent&lt;/strong&gt;&lt;/a&gt;
❗️❗️❗️ I’ve started a new series of daily short videos about software
development. I livestream them every weekday. Check out the playlist of videos
I have up there already including
&lt;a href="https://youtu.be/Dli_FisDdVU?list=PLV5CVI1eNcJgCrPH_e6d57KRUTiDZgs0u"&gt;npm tips&lt;/a&gt;,
&lt;a href="https://youtu.be/kCR3JAR7CHE?list=PLV5CVI1eNcJgCrPH_e6d57KRUTiDZgs0u"&gt;TDD with react-testing-library&lt;/a&gt;,
&lt;a href="https://youtu.be/JGXAvgVHC5A?list=PLV5CVI1eNcJgCrPH_e6d57KRUTiDZgs0u"&gt;webpack HMR&lt;/a&gt;,
and more!&lt;/li&gt;&lt;li&gt;&lt;a href="https://medium.com/@ken_wheeler/a-bitter-guide-to-open-source-a8e3b6a3c1c4"&gt;A bitter guide to open source&lt;/a&gt;
by &lt;a href="https://twitter.com/ken_wheeler"&gt;Ken Wheeler&lt;/a&gt;. It’s &lt;strong&gt;incredibly&lt;/strong&gt;
insightful (and full of cursing, you’ve been warned).&lt;/li&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;div style="display: flex;"&gt;
&lt;div style="padding-right: 20px;"&gt;
&lt;img
src="https://kentcdodds.com/images/small-circular-kent.png"
alt="Kent C. Dodds"
style="max-width: 80px; border-radius: 50%;"
/&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Kent C. Dodds&lt;/strong&gt; is a JavaScript software engineer and
teacher. He's taught hundreds of thousands of people how to make the world
a better place with quality software development tools and practices. He
lives with his wife and four kids in Utah.
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Learn more with Kent C. Dodds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/workshops"&gt;Live, professional workshops&lt;/a&gt;:
Join Kent C. Dodds from the comfort of your home for live remote workshops.
Tickets are limited! 🎟
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://testingjavascript.com"&gt;TestingJavaScript.com&lt;/a&gt;: Jump on
this self-paced workshop and learn the smart, efficient way to test any
JavaScript application. 🏆
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="margin-top=55px; font-style: italic;"&gt;(This article was posted to my blog at &lt;a href="https://kentcdodds.com/blog"&gt;https://kentcdodds.com/blog&lt;/a&gt;. You can &lt;a href="https://kentcdodds.com/blog/control-props-vs-state-reducers"&gt;read it online by clicking here&lt;/a&gt;.)&lt;/div&gt;
&lt;/div&gt;</content:encoded>
</item>
<item>
<title><![CDATA[Write your own code transform for fun and profit]]></title>
<description><![CDATA[If you haven't heard,
babel-plugin-macros
"enables zero-config, importable babel plugins." A few months ago, I published a
blog post about it on the official babel blog:
"Zero-config code transformation with babel-plugin-macros" . Since then…]]></description>
<link>https://kentcdodds.com/blog/write-your-own-code-transform</link>
<guid isPermaLink="false">https://kentcdodds.com/blog/write-your-own-code-transform</guid>
<pubDate>Mon, 04 Jun 2018 00:00:00 GMT</pubDate>
<content:encoded>&lt;div style="width: 100%; margin: 0 auto; max-width: 800px; padding: 40px 40px;"&gt;
&lt;p&gt;If you haven&amp;#x27;t heard,
&lt;a href="https://github.com/kentcdodds/babel-plugin-macros"&gt;&lt;code&gt;babel-plugin-macros&lt;/code&gt;&lt;/a&gt;
&amp;quot;enables zero-config, importable babel plugins.&amp;quot; A few months ago, I published a
blog post about it on the official babel blog:
&lt;a href="https://babeljs.io/blog/2017/09/11/zero-config-with-babel-macros"&gt;&amp;quot;Zero-config code transformation with babel-plugin-macros&amp;quot;&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Since then, there have been a few exciting developments:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;You can use it with a create-react-app application&lt;/strong&gt; (v2 beta) because
it&amp;#x27;s now included by default in the beta version of
&lt;a href="https://www.npmjs.com/package/babel-preset-react-app"&gt;&lt;code&gt;babel-preset-react-app&lt;/code&gt;&lt;/a&gt;
(which is what create-react-app v2 beta is using!)&lt;/li&gt;&lt;li&gt;It &lt;a href="https://github.com/fkling/astexplorer/pull/303"&gt;was added&lt;/a&gt; as an
optional transform to &lt;a href="https://astexplorer.net"&gt;astexplorer.net&lt;/a&gt; by
&lt;a href="https://twitter.com/FWeinb"&gt;@FWeinb&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Up until now, only early adopters have tried to
&lt;a href="https://github.com/kentcdodds/babel-plugin-macros/blob/master/other/docs/author.md"&gt;write a macro&lt;/a&gt;,
though there are a fair amount of
&lt;a href="https://github.com/kentcdodds/babel-plugin-macros/blob/master/other/docs/user.md"&gt;people using&lt;/a&gt;
the growing list of
&lt;a href="https://github.com/kentcdodds/babel-plugin-macros/blob/master/other/docs/macros.md"&gt;existing macros&lt;/a&gt;.
There are tons of awesome things you can do with &lt;code&gt;babel-plugin-macros&lt;/code&gt;, and I
want to dedicate this newsletter to showing you how to get started playing
around with writing your own.&lt;/p&gt;&lt;p&gt;Let&amp;#x27;s start off with a contrived macro that can split a string of text and
replace every space with &lt;code&gt;🐶&lt;/code&gt;. We&amp;#x27;ll call it &lt;code&gt;gemmafy&lt;/code&gt; because my dog&amp;#x27;s name is
&amp;quot;Gemma.&amp;quot; Woof!&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Go to &lt;a href="https://astexplorer.net"&gt;astexplorer.net&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Make sure the language is set to &lt;code&gt;JavaScript&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Make sure the parser is set to &lt;code&gt;babylon7&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Enable the transform and set it to &lt;code&gt;babel-macros&lt;/code&gt; (or &lt;code&gt;babel-plugin-macros&lt;/code&gt;
as soon as &lt;a href="https://github.com/fkling/astexplorer/pull/318"&gt;this is merged&lt;/a&gt;)&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Then copy/paste this in the source (top left) code panel:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;import gemmafy from &amp;#x27;gemmafy.macro&amp;#x27;
console.log(gemmafy(&amp;#x27;hello world&amp;#x27;))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And copy/paste this in the transform (bottom left) code panel:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;module.exports = createMacro(gemmafyMacro)
function gemmafyMacro({references, state, babel}) {
references.default.forEach(referencePath =&amp;gt; {
const [firstArgumentPath] = referencePath.parentPath.get(&amp;#x27;arguments&amp;#x27;)
const stringValue = firstArgumentPath.node.value
const gemmafied = stringValue.split(&amp;#x27; &amp;#x27;).join(&amp;#x27; 🐶 &amp;#x27;)
const gemmafyFunctionCallPath = firstArgumentPath.parentPath
const gemmafiedStringLiteralNode = babel.types.stringLiteral(gemmafied)
gemmafyFunctionCallPath.replaceWith(gemmafiedStringLiteralNode)
})
}
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Alternatively, you can
&lt;a href="https://astexplorer.net/#/gist/9d287441b6bd345f9e113c9c3b2b2aee/d5ebca867a522f8aa0120643883b97b83ee23fb4"&gt;open this&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;TADA 🎉! You&amp;#x27;ve written your (probably) very first babel plugin via a macro!&lt;/p&gt;&lt;p&gt;Here&amp;#x27;s the output that you should be seeing (in the bottom right panel):&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;console.log(&amp;#x27;hello 🐶 world&amp;#x27;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You&amp;#x27;ll notice that &lt;code&gt;babel-plugin-macros&lt;/code&gt; will take care of removing the import
at the top of the file for you, and our macro replaced the &lt;code&gt;gemmafy&lt;/code&gt; call with
the string.&lt;/p&gt;&lt;p&gt;So here&amp;#x27;s your challenge. Try to add this:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;console.log(gemmafy(&amp;#x27;hello world&amp;#x27;, &amp;#x27;world goodbye&amp;#x27;))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Right now that&amp;#x27;ll transpile to:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;console.log(&amp;#x27;hello 🐶 world&amp;#x27;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Your job is to make it do this instead:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;console.log(&amp;#x27;hello 🐶 world&amp;#x27;, &amp;#x27;goodbye 🐶 world&amp;#x27;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;From there, you can play around with it and do a lot of fun things!&lt;/p&gt;&lt;p&gt;If you want to see more of the capabilities, then copy this in the source (top
left):&lt;/p&gt;&lt;pre&gt;&lt;code class="language-jsx"&gt;import myMacro, {JSXMacro} from &amp;#x27;AnyNameThatEndsIn.macro&amp;#x27;
// (note: in reality, the AnyNameThatEndsIn.macro should be the name of your package
// for example: `codegen.macro`)
const functionCall = myMacro(&amp;#x27;Awesome&amp;#x27;)
const jsx = &amp;lt;JSXMacro cool=&amp;quot;right!?&amp;quot;&amp;gt;Hi!&amp;lt;/JSXMacro&amp;gt;
const templateLiteral = myMacro`hi ${&amp;#x27;there&amp;#x27;}`
literallyAnythingWorks(myMacro)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And copy/paste this in the transform (bottom left) code panel:&lt;/p&gt;&lt;pre&gt;&lt;code class="language-js"&gt;module.exports = createMacro(myMacro)
function myMacro({references, state, babel}) {
// `state` is the second argument you&amp;#x27;re passed to a visitor in a
// normal babel plugin. `babel` is the `@babel/core` module.
// do whatever you like to the AST paths you find in `references`.
// open up the console to see what&amp;#x27;s logged and start playing around!
// references.default refers to the default import (`myMacro` above)
// references.JSXMacro refers to the named import of `JSXMacro`
const {JSXMacro = [], default: defaultImport = []} = references
defaultImport.forEach(referencePath =&amp;gt; {
if (referencePath.parentPath.type === &amp;#x27;TaggedTemplateExpression&amp;#x27;) {
console.log(
&amp;#x27;template literal contents&amp;#x27;,
referencePath.parentPath.get(&amp;#x27;quasi&amp;#x27;),
)
} else if (referencePath.parentPath.type === &amp;#x27;CallExpression&amp;#x27;) {
if (referencePath === referencePath.parentPath.get(&amp;#x27;callee&amp;#x27;)) {
console.log(
&amp;#x27;function call arguments (as callee)&amp;#x27;,
referencePath.parentPath.get(&amp;#x27;arguments&amp;#x27;),
)
} else if (
referencePath.parentPath.get(&amp;#x27;arguments&amp;#x27;).includes(referencePath)
) {
console.log(
&amp;#x27;function call arguments (as argument)&amp;#x27;,
referencePath.parentPath.get(&amp;#x27;arguments&amp;#x27;),
)
}
} else {
// throw a helpful error message or something :)
}
})
JSXMacro.forEach(referencePath =&amp;gt; {
if (referencePath.parentPath.type === &amp;#x27;JSXOpeningElement&amp;#x27;) {
console.log(&amp;#x27;jsx props&amp;#x27;, {
attributes: referencePath.parentPath.get(&amp;#x27;attributes&amp;#x27;),
children: referencePath.parentPath.parentPath.get(&amp;#x27;children&amp;#x27;),
})
} else {
// throw a helpful error message or something :)
}
})
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Next, open up your developer console and check out the console logs. Have fun
with that!&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Alternatively, you can just
&lt;a href="https://astexplorer.net/#/gist/6efcadfda8975787d515a4a37c1a600a/635ba8b54af89d52171739c43a9a8a41627d461a"&gt;go here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;I think there are a LOT of really cool places we can go with this technology. I
didn&amp;#x27;t spend any time in this newsletter talking about the &lt;em&gt;why&lt;/em&gt; behind macros
or giving you ideas. I&amp;#x27;ll link to some resources for ideas below. The basic idea
is if there&amp;#x27;s a way that you can pre-compile some of your operations, then you
can improve runtime performance/bundle size of your application. In addition,
this allows you to do some things at build time when you have access to the file
system. The possibilities are really endless and we&amp;#x27;re just getting started!
Enjoy!&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Learn more about ASTs from me&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://youtu.be/nlAHtAQlFGk?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;All about macros with babel-plugin-macros 🎣 (talk at ReactJS Utah)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://frontendmasters.com/workshops/code-transformation-linting-asts"&gt;Code Transformation and Linting Course on Frontend Masters&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/-iA7TAUGn2Y?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;Code Transformation and Linting Workshop (very rough practice run)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/VBscbcm2Mok?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf"&gt;Writing custom Babel and ESLint plugins with ASTs (talk at Open West 2017)&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Things to not miss&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://youtube.com/watch?list=PLCC436JpVnK3xH_ArpIjdkYDGwWNkVa73&amp;amp;v=aOWIJ4Mgb2k"&gt;React Europe Talks Day 1&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/WYWVGQKnz5M?list=PLCC436JpVnK1X7atG6EIz467Evs4TMX_5"&gt;React Europe Talks Day 2&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/WYWVGQKnz5M"&gt;Stop writing code — Sunil Pai aka @threepointone at @ReactEurope 2018&lt;/a&gt; — See
the part where &lt;a href="https://twitter.com/threepointone"&gt;Sunil&lt;/a&gt; talks about the
origin story of &lt;code&gt;babel-plugin-macros&lt;/code&gt;&lt;a href="https://youtu.be/WYWVGQKnz5M?t=8m57s"&gt;starting at 8m57s&lt;/a&gt;. (Also, I love you
too Sunil 😍)&lt;/li&gt;&lt;li&gt;&lt;a href="https://youtu.be/NhmrbpVKgdQ?list=LLz-BYvuntVRt_VpfR6FKXJw"&gt;Pre-evaluate code at build time&lt;/a&gt;
from &lt;a href="http
View raw

(Sorry about that, but we can’t show files that are this big right now.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment