<?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[Ben Ilegbodu]]></title>
        <description><![CDATA[Ben Ilegbodu uses his many years of frontend development experience to provide quality content to help you become a better frontend engineer.]]></description>
        <link>benmvp-58narrjea-benmvp-dev.vercel.app/</link>
        <image>
            <url>benmvp-58narrjea-benmvp-dev.vercel.app/icons/icon-192x192.png</url>
            <title>Ben Ilegbodu</title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/</link>
        </image>
        <generator>RSS for Node</generator>
        <lastBuildDate>Mon, 17 Aug 2026 05:41:26 GMT</lastBuildDate>
        <atom:link href="benmvp-58narrjea-benmvp-dev.vercel.app/blog/rss.xml" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[From Vibe Coding to Deliberation-First Coding with AI]]></title>
            <description><![CDATA[
You give the Agent a prompt. It writes 200 lines of code. You review it. The architecture is wrong. You explain what you actually meant. It rewrites everything. Still not quite right. It misunderstood your data model. **10 or more iterations later**, you've got working code... and a lingering feeling that you could have just written it yourself faster.

Sound familiar?

Here's the thing: **the problem isn't the Agent. It's the process.** The write-review-write loop is the easiest approach, but it's inefficient and error-prone because the Agent makes incorrect assumptions without sufficient context. Yes, tools like [Cursor's Plan Mode](https://cursor.com/docs/agent/modes) try to help by asking clarifying questions upfront, but they don't go deep enough on shared context and decision-making.

There's a better way. I call it **deliberation-first coding**: structured conversations with AI Agents that front-load shared context so the Agent implements _your_ decisions correctly the first time. The key insight? **The best AI conversations happen before any code is written.**

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/deliberate-coding-ai-agents</link>
            <guid isPermaLink="false">deliberate-coding-ai-agents</guid>
            <category><![CDATA[genai]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[developer-experience]]></category>
            <category><![CDATA[agent]]></category>
            <category><![CDATA[cursor]]></category>
            <category><![CDATA[claude]]></category>
            <category><![CDATA[vscode]]></category>
            <category><![CDATA[architecture-driven-development]]></category>
            <category><![CDATA[engineering-practices]]></category>
            <category><![CDATA[productivity]]></category>
            <category><![CDATA[skills]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Being Sneaky with GenAI]]></title>
            <description><![CDATA[
The AI hype cycle has convinced us that every app needs a conversational interface, a RAG pipeline, or an autonomous agent. Meanwhile, most of us are just trying to ship features, fix bugs, and (just) maybe reduce the amount of repetitive nonsense we do every day. The reality? **The highest ROI AI integration isn't a chatbot. It's the stuff users don't even notice.**

I call it "Sneaky AI": using simple LLM API calls to eliminate toil, generate intelligent defaults, and make your existing features feel magical—without rewriting your architecture or hiring a PhD. If you're interested, I gave a talk on it at [All Things Open AI 2025](https://2025.allthingsai.org/) entitled ["Sneaky Ways to Integrate GenAI"](https://www.benmvp.com/ato-sneaky-ai).

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/being-sneaky-with-genai</link>
            <guid isPermaLink="false">being-sneaky-with-genai</guid>
            <category><![CDATA[genai]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[developer-experience]]></category>
            <category><![CDATA[developer-tools]]></category>
            <category><![CDATA[openai]]></category>
            <category><![CDATA[gpt]]></category>
            <category><![CDATA[gemini]]></category>
            <category><![CDATA[anthropic]]></category>
            <category><![CDATA[claude]]></category>
            <category><![CDATA[seo]]></category>
            <category><![CDATA[automation]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Thu, 08 Jan 2026 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[How GenAI is shifting architecture left]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/genai-shift-left-software-architecture</link>
            <guid isPermaLink="false">genai-shift-left-software-architecture</guid>
            <category><![CDATA[genai]]></category>
            <category><![CDATA[architecture]]></category>
            <category><![CDATA[architecture-driven-development]]></category>
            <category><![CDATA[spec-driven-development]]></category>
            <category><![CDATA[meta-spec]]></category>
            <category><![CDATA[shift-left]]></category>
            <category><![CDATA[developer-experience]]></category>
            <category><![CDATA[refactoring]]></category>
            <category><![CDATA[engineering-practices]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Wed, 12 Nov 2025 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Have We Finally Reached the Mythical "10x Developer"?]]></title>
            <description><![CDATA[
For decades, our industry has been obsessed with the "10x developer" -- that mythical engineer who's supposedly 10 times more productive than the rest of us. It's always been a bit of a loaded concept if you ask me, often rewarding behaviors that aren't necessarily great for teams or codebases. But with the arrival of powerful GenAI coding assistants, the "10x" conversation is back in full force.

Here's the thing though: **we're thinking about it all wrong**.

When I first started hearing the AI hype, it seemed like everyone was defining a 10x developer as someone who can crank out 10 times more code. As someone who now uses GenAI for 90%+ of my output (yep, including writing this blog post!), I can tell you that's a complete trap. If we're optimizing for lines of code, we're basically optimizing for bloat, complexity, and a whole lot of future technical debt. Not exactly what I'd call "winning." 😅

Don't get me wrong -- the GenAI revolution absolutely does unlock 10x potential. But it's not just about volume. It's about being 10x more **thoughtful**, 10x more **robust**, and 10x more **innovative** in how we approach our work.

I've been thinking about this a lot lately, and I see this new kind of productivity happening across four key areas.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/mythical-10x-developer</link>
            <guid isPermaLink="false">mythical-10x-developer</guid>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[productivity]]></category>
            <category><![CDATA[developer-experience]]></category>
            <category><![CDATA[career-growth]]></category>
            <category><![CDATA[software-engineering]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Tue, 07 Oct 2025 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Mock all functions in a JavaScript module except one using Jest]]></title>
            <description><![CDATA[
There are times in a Jest test when we have a module where the majority of the functions need to be mocked, but we have one (or two) that need to be left alone. Likely in this case most of the functions have side effects. But there are some that are normal input/output (aka "pure") functions that need to work when they are called during a test run. We can use a combination of [`jest.requireActual()`](https://jestjs.io/docs/jest-object#jestrequireactualmodulename) and [`jest.createMockFromModules()`](https://jestjs.io/docs/jest-object#jestcreatemockfrommodulemodulename).

```js
// app.test.js

// create a mock of the `../utils/players` module that is called
// from `app.js` (the code being tested)
jest.mock('../utils/players', () => {
  // use auto-mocking system to get an object that mocks all
  // of the module's functions, just like what `jest.mock()`
  // (w/ no parameters) would do
  const allAutoMocked = jest.createMockFromModule('../utils/players')

  // grab all the *real* implementations of the module's functions
  // in an object
  const actual = jest.requireActual('../utils/players')

  // return a new module implementation
  return {
    __esModules: true,

    // first start with all of the module's functions auto-mocked
    ...allAutoMocked,

    // then optionally include any override module mocks
    getPlayers: jest.fn(() => []),
    getTeams: jest.fn(() => []),

    // lastly override w/ any of the module's functions that
    // we want to use the *real* implementations for
    formatPlayerName: actual.formatPlayerName,
  }
})
```

If you are like how I was looking for how in Jest to mock a JavaScript module to keep the real implementation of one function, but mock the rest, here's your answer! 🎉 Feel free to return to your test code so you can continue writing high-quality tests. 😉 But... if you're interested in learning how all of this works, by all means, read on!

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/mock-all-functions-module-except-one-jest</link>
            <guid isPermaLink="false">mock-all-functions-module-except-one-jest</guid>
            <category><![CDATA[testing]]></category>
            <category><![CDATA[jest]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 01 May 2022 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Create one-off releases with semantic-release]]></title>
            <description><![CDATA[
I use [`semantic-release`](https://github.com/semantic-release/semantic-release) for both personal and work projects to automate version management and publishing of packages. It's nice because it takes care of the entire release flow, like figuring out the [next version](https://docs.npmjs.com/cli/v8/commands/npm-version) (using [Angular Commit Message Conventions](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-format)), auto-generating GitHub release notes, and finally [publishing the package](https://docs.npmjs.com/cli/v8/commands/npm-publish) to the npm registry.

I like `semantic-release` for the handful of personal projects I work on because package publishing is a part of DivOps that I don't want to deal with. Developing the library is enough. 😃 At work `semantic-release` **provides a centralized point in CI that handles releasing a package** so that individual developers aren't trying to figure it out on their machines.

The default `semantic-release` configuration does all that I described, so initially I could release without an explicit config. Then I use [npx](https://www.npmjs.com/package/npx) to run it in CI. For example, a `release.yml` [Github workflow](https://github.com/features/actions):

```yml
name: Release

on: push

jobs:
  main:
    name: NPM Release
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Use Node v16
        uses: actions/setup-node@v2
        with:
          node-version: '16'

      - name: Install dependencies
        run: npm ci

      - name: Run unit tests
        run: npm test
        env:
          CI: true

      - name: Run integration tests
        run: npm run integrate
        env:
          CI: true

      - name: Release new version to NPM
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
        # highlight-next-line
        run: npx semantic-release
```

> I don't even install `semantic-release` as a dependency in the project. I always use the latest version.

However, sadly the default configuration [still uses `master` as the default branch](https://github.com/semantic-release/semantic-release/issues/1581). Since all of my repos use `main` as the default branch, I now need a `release.config.js` to configure the [supported branches](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/configuration.md#branches).

```js {3}
module.exports = {
  branches: [
    'main',
    'next',
    'next-major',
    // version number branches will release that version
    '+([0-9])?(.{+([0-9]),x}).x',
    { name: 'beta', prerelease: true },
    { name: 'alpha', prerelease: true },
  ],
}
```

And because all of my libs are written in TypeScript, I also have a build step before releasing the pacakge. The build step allows the project to transpile TypeScript into vanilla JavaScript and auto-generate TypeScript declaration files (`*.d.ts`). As a result, **I need to specifically configure the [`@semantic-release/npm` plugin](https://github.com/semantic-release/npm) to specify the build directory (typically `lib/` for me)**. But to configure the plugin, I also must include all of the [plugins](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/configuration.md#plugins) used by default.

```js {19-21}
module.exports = {
  branches: [
    'main',
    'next',
    'next-major',
    '+([0-9])?(.{+([0-9]),x}).x',
    { name: 'beta', prerelease: true },
    { name: 'alpha', prerelease: true },
  ],

  plugins: [
    // analyzes commits w/ conventional-changelog
    '@semantic-release/commit-analyzer',

    // generates a changelog w/ conventional-changelog
    '@semantic-release/release-notes-generator',

    // publishes the npm package from the specified folder
    ['@semantic-release/npm', {
      pkgRoot: './lib'
    }]

    // Publishes changelog as a GitHub release and
    // comments on released Pull Requests & Issues
    '@semantic-release/github',
  ],
}
```

> FYI: at work I also use [`semantic-release-slack-bot`](https://github.com/juliuscc/semantic-release-slack-bot) to get release notifications in Slack from a Slack bot, but I'm leaving it out to simplify the discussion.

With the addition of the build step, the `release.yml` Github workflow now looks like:

```yml
name: Release

on: push

jobs:
  main:
    name: NPM Release
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Use Node v16
        uses: actions/setup-node@v2
        with:
          node-version: '16'

      - name: Install dependencies
        run: npm ci

      - name: Run unit tests
        run: npm test
        env:
          CI: true

      - name: Run integration tests
        run: npm run integrate
        env:
          CI: true

      # highlight-start
      - name: Build package
        run: npm run build
      # highlight-end

      - name: Release new version to NPM
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
        run: npx semantic-release
```

Because `semantic-release` relies on a strict commit format (by default [Angular Commit Message Conventions](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-format)) in order to auto-determine the next version, **I also set up all of my GitHub projects to only support [squash merge commits](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/about-pull-request-merges#squash-and-merge-your-pull-request-commits) in Pull Requests**. I've found that it's the least painful way to ensure developers use the proper commit format because I also add another GitHub workflow to validate the Pull Request title using the [`amannn/action-semantic-pull-request`](https://github.com/amannn/action-semantic-pull-request) GitHub action. An example `validate-pr.yml` workflow file looks like:

```yml
name: Pull Request

on:
  pull_request_target:
    types:
      - opened
      - edited
      - synchronize

jobs:
  main:
    name: Validate PR title
    runs-on: ubuntu-latest
    steps:
      ## highlight-next-line
      - uses: amannn/action-semantic-pull-request@v4
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/create-one-off-releases-semantic-release</link>
            <guid isPermaLink="false">create-one-off-releases-semantic-release</guid>
            <category><![CDATA[divops]]></category>
            <category><![CDATA[semantic]]></category>
            <category><![CDATA[release]]></category>
            <category><![CDATA[one]]></category>
            <category><![CDATA[off]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 13 Mar 2022 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Putting test files in the pages folder in a Next.js app]]></title>
            <description><![CDATA[
When developing Next.js apps I want to be able to include other files within the `src/pages` directory besides the [page React components](https://nextjs.org/docs/basic-features/pages) or [API routes](https://nextjs.org/docs/api-routes/introduction). I'm perfectly fine putting components in `src/components` and helper functions in `src/utils`. But I like to co-locate other files with my pages and API routes.

Instead of creating a parallel `__tests__` folder, I like putting my `*.test.ts` or `*.test.tsx` [Jest unit tests](https://jestjs.io/) next to whatever it is that I'm testing. That works great in `src/components`, `src/utils` or any other location outside of `src/pages`. Similarly, I like putting my [Storybook stories](https://storybook.js.org/) (`*.stories.tsx`) next to my React components, including my page components (made possible by [Storybook Addon Next Router](https://storybook.js.org/addons/storybook-addon-next-router)).

But when I add these files within `src/pages` or `src/pages/api` and run `next build`, I get the following error:

```text
Build error occurred

Error: Build optimization failed: found page without a
React Component as default export in

pages/my/plan.stories

See https://nextjs.org/docs/messages/page-without-valid-component
for more info.
```

It's pretty nice that the error leads me to a place where I can find more info. I love when frameworks do this. But when I visit the [Page Without Valid React Component](https://nextjs.org/docs/messages/page-without-valid-component) page it gives a rather short explanation as to why the error ocurred, and some possible ways to fix it. The problem is that all the possible ways to fix it assume I somehow screwed up! 😢

I mean I guess I did screw up by putting other files in the `src/pages` folder, but it seems like something that should be allowed! Why is Next.js so picky about what files go in there? I guess since Next uses [page-based routing](https://nextjs.org/docs/basic-features/pages) it makes sense that it will have no way of interpreting page component files from test files or Storybook stories.

So for the longest I just accepted my fate and put my stories in a sibling `src/page-stories` directory and just avoided writing unit tests, moving nearly everything into `src/utils`. But it felt a bit clunky.

Then a coworker showed me a workaround! The [`pageExtensions` configuration](https://nextjs.org/docs/api-reference/next.config.js/custom-page-extensions) allows us to alter the default list of valid page extensions (`.tsx`, `.ts`, `.jsx`, and `.js`). The config option is aimed at tools like [`@next/mdx`](https://github.com/vercel/next.js/tree/canary/packages/next-mdx), which have files that end in `.mdx`. But we can take advantage of it to let us put non-page files in the `src/pages` folder as well. And it's right there in the [docs](https://nextjs.org/docs/api-reference/next.config.js/custom-page-extensions#including-non-page-files-in-the-pages-directory).

We add special extensions for the page components and API routes to help Next.js distinguish them from all of the other files.

```js
module.exports = {
  pageExtensions: [
    // `.page.tsx` for page components
    'page.tsx',
    // `.api.ts` for API routes
    'api.ts',
  ],
}
```

Because I exclusively develop in TypeScript, I only have TypeScript extensions. So all of my pages end in `.page.tsx`, such as `src/pages/my/plan.page.tsx`. And any of my API routes end in `.api.ts`, such as `src/pages/api/client/auth.api.ts`. I give the API routes their own extension, just for added clarity. And because page components will always have JSX, there's no need for `.page.ts`. Likewise, since API routes should never have JSX, there's no need for `.api.tsx`.

Now I can have `plan.page.tsx`, `plan.test.tsx` and `plan.stories.tsx` all in the same `src/pages/my` folder! And the cool thing is if I want to add a `utils.ts` or `constants.ts` in the `src/pages` folder, it will also work. Who knew something so simple could be so exciting? 😂

Keep in mind, though, that this change also has to apply to any [Custom App](https://nextjs.org/docs/advanced-features/custom-app) (`src/pages/_app.tsx`), [Custom Document](https://nextjs.org/docs/advanced-features/custom-document) (`src/pages/_document.tsx`), and [Custom Error Pages](https://nextjs.org/docs/advanced-features/custom-error-page) (`src/pages/404.tsx` & `src/pages/500.tsx`) that we've defined. They'll all need the `.pages.tsx` extension.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/putting-test-files-pages-folder-nextjs-app</link>
            <guid isPermaLink="false">putting-test-files-pages-folder-nextjs-app</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[nextjs]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 13 Feb 2022 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Avoiding React act warning when accessibility testing next/link with jest-axe]]></title>
            <description><![CDATA[
Recently when adding accessibility tests with [`jest-axe`](https://github.com/nickcolley/jest-axe) to a React component, I ran into the dreaded [`act()` warning](https://reactjs.org/link/wrap-tests-with-act):

```text {11-14}
 FAIL  src/components/Link.test.tsx
  ✕ is accessible (70 ms)

  ● is accessible

    Expected test not to call console.error().

    If the warning is expected, test for it explicitly by mocking it
    out using jest.spyOn(console, 'error') and test that the warning occurs.

    Warning: An update to Link inside a test was not wrapped in act(...).

    When testing, code that causes React state updates should be wrapped
    into act(...):

    act(() => {
      /* fire events that update state */
    });
    /* assert on the output */

    This ensures that you're testing the behavior the user would see in the
    browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
      at Link (.../node_modules/next/client/link.tsx:131:19)
      at Link (.../src/components/Link.tsx:15:5)
```

This specific test was testing a React component that wrapped [`next/link`](https://nextjs.org/docs/api-reference/next/link).

```js {14}
import { render, screen } from '@testing-library/react'
import { axe } from 'jest-axe'
import Link from './Link'

it('is accessible', async () => {
  const { container } = render(
    <Link href="https://www.benmvp.com">contents</Link>,
  )

  expect(screen.getByRole('link')).toHaveAttribute(
    'href',
    'https://www.benmvp.com',
  )
  expect(await axe(container)).toHaveNoViolations()
})
```

**But it turns out that any component that rendered a `next/link` had this exact same problem.** I googled around for some combination of "jest-axe", "next/link", and "act()" and surprisingly found very little. But there was nothing that was helpful or provided a solution.

If I were to use [`act()`](https://testing-library.com/docs/react-testing-library/api#act) the way the warning message suggested, it would look something like:

```js {13,15}
import { act, render, screen } from '@testing-library/react'
import { axe } from 'jest-axe'
import Link from './Link'

it('is accessible', async () => {
  const { container } = render(<Link href="/">contents</Link>)

  expect(screen.getByRole('link')).toHaveAttribute(
    'href',
    'https://www.benmvp.com',
  )

  await act(async () => {
    expect(await axe(container)).toHaveNoViolations()
  })
})
```

But I didn't want to have to write this `act()` code every time I decided to use `jest-axe` with a component that rendered a `next/link` (either directly or indirectly). Plus it would be highly likely that my teammates would get tripped up by it even if I did document the problem.

**[React Testing Library](https://testing-library.com/docs/react-testing-library/intro/) wraps all of its [user events](https://testing-library.com/docs/ecosystem-user-event) with `act()` so that we don't have to.** But even still, the `act()` warning usually happens when we perform some non-UI action in a test that causes the component to re-render. All I did was render and add an accessibility assertion. The component shouldn't have been re-rendering.

Well, after lots of debugging and sleuthing (more details below if you're interested), I finally came up with a workaround that avoided using `act()` everywhere. It requires installing [`react-intersection-observer`](https://github.com/thebuilder/react-intersection-observer) and using its test utils in the Jest configuration.

```js {3,7,15,16}
// jest.config.js
module.exports = {
  setupFiles: ['<rootDir>/jest.setupFiles.js'],
  setupFilesAfterEnv: [
    '@testing-library/jest-dom',
    'jest-axe/extend-expect',
    'react-intersection-observer/test-utils',
    '<rootDir>/jest.setupFilesAfterEnv.ts',
  ],
}

// jest.setupFiles.js
import { defaultFallbackInView } from 'react-intersection-observer'

global.IntersectionObserver = jest.fn()
defaultFallbackInView(false)
```

These few lines solve the problem! **It seems so simple, but it took me hours of struggling and wondering if I'd even find a workaround.** The solution is definitely not straightforward. So if you're having this problem right now and just need an answer so you can move on, there you have it! 😃

But if you'd like to know why it works and why it was even failing in the first place, feel free to read on! I want to take you through (a condensed version of) my debugging process so you can learn how to debug 3rd-party code, learn some things about JavaScript, and hopefully add some tools to your DivOps setup.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/avoiding-react-act-warning-when-accessibility-testing-next-link-jest-axe</link>
            <guid isPermaLink="false">avoiding-react-act-warning-when-accessibility-testing-next-link-jest-axe</guid>
            <category><![CDATA[divops]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[testing]]></category>
            <category><![CDATA[accessibility]]></category>
            <category><![CDATA[a11y]]></category>
            <category><![CDATA[nextjs]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 30 Jan 2022 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Handling the React server hydration mismatch error]]></title>
            <description><![CDATA[
I was recently working on a React component in a shared component library. The component library up until recently had only been used in client-side rendered apps (think [Create React App](https://create-react-app.dev/)). However, once it started being used in server-sie rendered apps (think [Next.js](https://nextjs.org/)), I started getting the React server hydration mismatch error. For prop errors, the warning looks something like:

```text
Warning: Prop `className` did not match. Server: "positive" Client: "zero"
```

or for text content:

```text
Warning: Text content did not match. Server: "0" Client: "5"
```

Unlike most React warnings, this warning doesn't link to a doc explaining the warning in greater details with some suggested solutions (like for instance the [Invalid Hook Call Warning](https://reactjs.org/warnings/invalid-hook-call-warning.html)). There _are_ docs on the [`hydrate()`](https://reactjs.org/docs/react-dom.html#hydrate) function that does the client-side hydrating on a server-rendered app, but we'd have to know to find it.

Let's walk through what's happening in my component. Here is a representation of the code:

```js
const Incrementer = () => {
  // initialize the state from a value in `localStorage`
  // if it exists
  const [value, setValue] = useState(() => {
    // using lazy state initialization so that we only
    // read from `localStorage` the very first render
    let initValue

    // test for the presence of `window` because it
    // won't exist in Node for server-side rendering.
    // we'll only get the `localStorage` value in
    // the browser
    if (typeof window === 'object') {
      initValue = window.localStorage.getItem('value')
    }

    return initValue ? parseInt(initValue, 10) : 0
  })
  let className = 'zero'

  if (value < 0) {
    className = 'negative'
  } else if (value > 0) {
    className = 'positive'
  }

  return (
    <div className={className}>
      <button onClick={() => setValue((curValue) => curValue - 1)}>-</button>
      <span>{value}</span>
      <button onClick={() => setValue((curValue) => curValue + 1)}>+</button>
    </div>
  )
}
```

> FYI: This is not the **actual** code in the component library. The actual code is a `useMedia()` Hook for tracking the match state of a media query in Javascript. That code is quite involved, so I've simplified it with this example.

The component is a very standard minimal example that's used to show interactivity in a React component. The only difference is that it optionally retrieves its initial value from [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) using [lazy state initialization](https://reactjs.org/docs/hooks-reference.html#lazy-initial-state). If you don't know what lazy state initialization is or when you should use it, check out a previous post of mine called [Four characters can optimize your React component](https://www.benmvp.com/blog/four-characters-optimize-react-component/).

**Because `window` doesn't exist in the Node environment during server-side rendering, the component first has to check if `window` exists before accessing `localStorage`.** Therefore, when the component is rendered server-side, `value` will always be `0`, the default value (`className` will also be `"zero"`). And when the component renders on the client-side, `window` will exist, and it can read from `localStorage` to get the initial value.

The fact that React components can render server-side is pretty cool. But unfortunately this code doesn't quite work as expected. The server-side render actually works fine with the default `0` value. Also, if the component was only rendered client-side, the component renders fine as well (reading from `localStorage` if the stored value exists). But it's when the component is _hydrating_ on the client from server rendered HTML that we have a problem. **React expects the initial render on the client to match what was rendered on the server.** To get a better understanding of hydration, read [Josh W. Comeau](https://twitter.com/joshwcomeau)'s blog post, [The Perils of Rehydration](https://www.joshwcomeau.com/react/the-perils-of-rehydration/#two-pass-rendering).

But if the component gets a value from `localStorage` (let's say `"15"`) with the initialization of state, both `value` (`15`) and `className` (`"positive"`) will be different than the default values (`0` and `"zero"`) rendered on the server. And when what is hydrated on the client differs from what was server-rendered, we get the server hydration error.

```text
Warning: Text content did not match. Server: "0" Client: "15"
```

And the real error isn't actually the warning. The real problem is that our UI is "stale." **React doesn't update the UI to match the props that were rendered differently by the client during hydration.** Instead it keeps the attributes that were already in the markup from the server-side rendering. React _does_ update the text content, however. So in our example, `15` will be rendered in the `<span>`. But because it does _not_ update props, the `className` will still be `"zero"` (instead of `"positive"`).

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/handling-react-server-mismatch-error</link>
            <guid isPermaLink="false">handling-react-server-mismatch-error</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[ssr]]></category>
            <category><![CDATA[csr]]></category>
            <category><![CDATA[component]]></category>
            <category><![CDATA[hydration]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Mon, 17 Jan 2022 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Creating custom generic TypeScript utility types]]></title>
            <description><![CDATA[
I was recently working on my latest project, which uses [Firestore](https://firebase.google.com/) as its NoSQL database. The way the data is stored in Firestore is _almost_ how I represent the data in app. The only difference is that Firestore has its own object for modeling dates that is different than the JavaScript [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) object. So in order to avoid having to write almost identical types for both the internal and Firestore representations of an object (and keep them in sync over time), I created a generic TypeScript utility type that would recursively replace all `Date` types to Firebase [`Timestamp`](https://github.com/firebase/firebase-js-sdk/blob/2e7586dd7320d48d4b58aa13b525ec4a599f87e2/packages/firestore/src/lite-api/timestamp.ts) types in any type whether it's an interface, array or something else.

```typescript
// A generic type that returns a new type by returning a
// `Timestamp` if the generic parameter is a `Date`.
// Or, if given an array type, it returns the same
// array type except replacing the item `Date` types w/
// `Timestamp` types. Does the same for object value
// types as well. Otherwise, just returns the type back.
type ToFirestore<MaybeDate> = MaybeDate extends Date
  ? Timestamp
  : MaybeDate extends Array<infer Item>
  ? Array<ToFirestore<Item>>
  : MaybeDate extends Record<string, any>
  ? { [Key in keyof MaybeDate]: ToFirestore<MaybeDate[Key]> }
  : MaybeDate
```

> See the code in action on the [TS Playground](https://www.typescriptlang.org/play?#code/PTAEFkHsGMGtQE4FMAOyDOSB2AXAhjgJaRaiQBmoeoAYoRjpMqAAYAqhAtkuvpyi1A4AniiQAoQriQJyeaElAduvPP1ABvcaB2IkeACYkANsNCZoJA+gBcoLAFdOAIxkAabbuSGTZrHixICytbeydXBHEAX3FxEFAAQVAAc2wZQmghUUUcAAsCPRwHBCx0KnskAHcssVBnM2Qikqlkqjiwdi4ePgFQQko8xVSsdMyUPAQ1JBwZPrLqFgARAiQWADp20AB5BDc+ymTCADdsKlIJybMRMT3CHELi0qFcxXQpzYu8K+zQJAAPBQoe7IFDGeQtZ6KO5ITisZYzQTXHigSrATadFQ9RHZdBrUCLSDIwbmKagchMMjOABWSGg9yOeGMDgk8SR8zKlSQxmMeK2gwQlUImD2VIcvAeJTKxKRdXksA2MrYkDoDCYSAAPOAvq54UgAHygAC8EG1SF1vz+Myw1nxK08AH4lF1VPxPHYtcIdSsLVabQkEJd1VJyLMAJIzTh6h2JANfdVKlXdNXq8MwvVRnTu03m-6+soAJVpTAM6t4CBaewCwgzoEdGlAAG0ANJIMxSUCwVsUE2es0rAC6dgT9CTyE12ZWzdb-YNMUzPa9M1iUhmsnkigACmDSFodJZuXhnEwCExQmWWg3+55oN4ZgY7LrPAYudMkAZ7Q+7TpCPfzDhy1gySeNwjKhLuuigAYKyfkuEHIOQdjnoBng6EidgAOTON4sByLw6GgAAPqAmEIA4WDQLk+FEehTLkZRhHEQYUgjAgVHEeg-hwOhnhRJeniqEUoToWx6FoFwEzCCJEwUccb7cTonCQEx5CEG+MESDo-jcIh-4tJ4kCVCxOkAUBOhHEKhDOIQxh3MIGFiQyMwiTZWCwAAtL4IkoA4zg2dA3ExJsAASkAnAgZBhawia8GqW4BIikDmEgUI4GUz4qVgdzEKQgp5OiyjdGovRsn0pCguuZCUEsKzYmI6DiDK0WMMgcWkMaw6qmOrVRg1PxIkk7XKiOMVjkhyRRjKSIAEJGkoQ2dRqjguDIl4TX12QAMKzR1o4avWWlIMZFZUKkdhLREoBRFGQA).

This post is the third post in a series on TypeScript generics. The first post introduced generics by [re-implementing lodash functions](/blog/understanding-typescript-generics-lodash-functions/). In the second post, we [learned TypeScript generics by rebuilding existing utility types](/blog/learn-typescript-generics-rebuilding-existing-utility-types/). Now in this final post we're creating our own custom generic utility types using everything we've learned.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/creating-custom-generic-typescript-utility-types</link>
            <guid isPermaLink="false">creating-custom-generic-typescript-utility-types</guid>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[generics]]></category>
            <category><![CDATA[conditional]]></category>
            <category><![CDATA[recursion]]></category>
            <category><![CDATA[expressions]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Tue, 21 Dec 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[TypeScript user-defined type guards to the rescue]]></title>
            <description><![CDATA[
Recently I was writing some TypeScript code where I needed to look at the user's preferred languages (using [`Navigator.languages`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/languages)) and compare it against my site's valid locales in order to determine which locale to display for internationalization (I18N). Here's what some of the implementation looked like:

```typescript
const ALL_LOCALES = [
  'en-US',
  'en-GB',
  'en-CA',
  'fr-CA',
  'fr-FR',
  'es-ES',
  'es-US',
] as const

// derive `Locale` type from `ALL_LOCALES` data
type Locale = typeof ALL_LOCALES[number]
// ⮑ "en-US" | "en-GB" | "en-CA" | "fr-CA" | "fr-FR" | "es-ES" | "es-US"

const DEFAULT_LOCALE: Locale = 'en-US'

// A `Set<string>` to make it easy to see if a language string
// is a valid locale
const VALID_LOCALES_LOOKUP = new Set<string>(ALL_LOCALES)

// user-defined type guard that takes in a language string and returns
// whether it is one of the valid locales
const isValidLocale = (language: string): language is Locale =>
  VALID_LOCALES_LOOKUP.has(language)

// finds the first user language that is a valid locale or the default locale
const getUserLocale = (): Locale =>
  navigator.languages.find(isValidLocale) || DEFAULT_LOCALE
```

To understand how this all works, we need to first understand [narrowing](https://www.typescriptlang.org/docs/handbook/2/narrowing.html) in TypeScript. **TypeScript's type system aims to make it as easy as possible to write typical JavaScript code without having to do too much to get type safety.** So if we have a variable that is a union of multiple types, we can use various different JavaScript constructs to _narrow_ down the type.

The simplest construct is [truthiness narrowing](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#truthiness-narrowing).

```typescript
const getTeamMessage = (team?: Team) => {
  // `team` has type `Team | undefined`

  if (team) {
    // Because `team` is "truthy" TS knows that
    // it *cannot* be `undefined`, so its type
    // is just `Team`
    return `Welcome ${team.name}!`
  }

  // Because of the `return` above, TS knows that
  // `team` can only be `undefined` here

  return 'Welcome!'
}
```

There's nothing really spectacular about the code. It's normal JavaScript, but TypeScript understands "JavaScript-isms." It's able to infer the type of `team` inside and after the `if` statement based on the [truthiness](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) condition.

Truthiness narrowing basically can only exclude `null` and `undefined` from a type, but there are other JavaScript constructs that can do more, like [`typeof` type guards](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#typeof-type-guards) and [`instanceof` narrowing](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#instanceof-narrowing).

```typescript
const log = (time: Date | string, message: string) => {
  // if `time` is an instance of the `Date` class, then TS knows
  // we can call `.toUTCString()` because it's a `Date` type. It also
  // knows that in the "else" case of the ternary, `time` is a `string`
  const timestamp = time instanceof Date ? time.toUTCString() : time
  // ⮑ `string`

  console.log(`[${timestamp}] ${message}`)
}

interface Option {
  value: string
  display: string
}

const getDisplay = (option: Option | string): string =>
  // if `option` is a JS object then TS infers that it's an `Option`
  // object. So in the "else" case, `option` must be a `string`
  typeof option === 'object' ? option.display : option
```

In both examples we're using built-in JavaScript operators that return rudimentary type information: [`typeof`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof) and [`instanceof`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof). Depending on the types in the unioned type, using one operator or the other can help TypeScript narrow down the possible types when you can call the method ([`.toUTCString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toUTCString)) or access the property that you care about.

But what happens if you have two objects types, neither of which are class instances? Using `typeof` or `instanceof` won't help. Depending on the properties of the objects, we can make use of [`in` operator narrowing](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#the-in-operator-narrowing).

```typescript
interface Team {
  name: string
  city: string
  revenue: number
}

interface Player {
  firstName: string
  lastName: string
  position: 'guard' | 'wing' | 'big'
  team: Team
}

const getName = (item: Team | Player) =>
  // if `item` has a `city` property, then TS infers that it's
  // a `Team` object because `Team` is the only object w/ that property.
  // As a result in the "else" case, `item` must be a `Player`
  'city' in item ? item.name : `${item.firstName} ${item.lastName}`
```

Both `Team` and `Player` are plain JavaScript objects so `instanceof` won't work and `typeof` will return `"object"` for both. However we can use the [`in` operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in) (also see [Using new-ish & lesser-known JavaScript operators to write concise code](/blog/using-javascript-operators-write-concise-code/) for more) to see if a unique property is on the `item` object. **Because `"city"` only exists on `Team` objects, TypeScript is now able to disambiguate the type and the ternary expression becomes fully type-safe.**

JavaScript isn't a fully-typed language so the built-in constructs can only help TypeScript so much. Sometimes we have to give TypeScript a hand with narrowing and define our own type guard. That's where [type predicates](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates) within user-defined type guards come in.

```typescript
const ALL_LOCALES = [
  'en-US',
  'en-GB',
  'en-CA',
  'fr-CA',
  'fr-FR',
  'es-ES',
  'es-US',
] as const

// derive `Locale` type from `ALL_LOCALES` data 🤓
type Locale = typeof ALL_LOCALES[number]
// ⮑ "en-US" | "en-GB" | "en-CA" | "fr-CA" | "fr-FR" | "es-ES" | "es-US"

const DEFAULT_LOCALE: Locale = 'en-US'

// A `Set<string>` to make it easy to see if a language string
// is a valid locale
const VALID_LOCALES_LOOKUP = new Set<string>(ALL_LOCALES)

// user-defined type guard that takes in a language string and returns
// whether it is one of the valid locales
const isValidLocale = (language: string): language is Locale =>
  VALID_LOCALES_LOOKUP.has(language)
```

> A trick to derive a union type from an array is to first mark the array with a [`const` assertion](/blog/use-cases-typescript-const-assertions/). Then using `typeof` plus `ARRAY_NAME[number]` will generate a union type. The `number` isn't the `number` type but instead a generic value for "all indices."

A `Locale` is one of a handful of specific `string`s (`"en-US"`, `"fr-FR"`, etc.) so there's no way for us to distinguish a `Locale` from a `string` with regular JavaScript. The `language is Locale` return type of `isValidLocale()` is the _type predicate_ that allows us to write actual code to determine if the parameter (`language`) is in fact the desired type (`Locale`). The function is the _user-defined type guard_. **The return value must be a boolean.** When `true`, the type predicate is true and TypeScript infers that the parameter is the desired type.

Like with the other narrowing examples, we could use the user-defined type guard in a simple conditional.

```typescript
const getUserLocale = (): Locale =>
  // if the language is a valid locale, TS now treats
  // `navigator.language` as a `Locale` even though it's
  // been defined as a `string`
  isValidLocale(navigator.language) ? navigator.language : DEFAULT_LOCALE
```

Typically [`Navigator.language`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/language) is a `string`. But with the user-defined type guard returning `true`, `navigator.language` is now narrowed to a `Locale`, a union of those locale strings.

The `navigator.language` property only returns the first of the user's preferred languages. Because its possible that their primary preferred language could be an invalid locale for my site, I needed to check all of their preferred languages using [`Navigator.languages`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/languages). This made the `getUserLocale()` function a bit more complicated.

```typescript
// finds the *first* user language that is a valid locale,
// or uses the default locale if a valid one can't be found
const getUserLocale = (): Locale =>
  // use the user-defined type guard as the test function for `.find()`. When
  // it returns true, TS infers that the found item is also a `Locale`.
  navigator.languages.find(isValidLocale) || DEFAULT_LOCALE
```

The `navigator.languages` property is a `string[]`. The [`.find()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find) method takes a test function that returns true when an array item passes the test. Because `isValidLocale` does the same thing, we can pass it to `.find()`. But since it's not just a regular function but a type predicate, TypeScript now knows that the found item in the `string[]` is specifically a `Locale`.

A user-defined type guard can also be used with [`.filter()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill) to not only filter down the elements but filter down the types as well.

```typescript
// returns a list of the user languages that are also valid locales
const getUserLocales = (): Locale[] =>
  // by using the user-defined type guard as the test function for
  //  .filter()` TS knows that the returned array can only be
  // `Locale` items
  navigator.languages.filter(isValidLocale)
```

> I wrote a post almost exactly a year ago called [Filtering undefined elements from an array in TypeScript](/blog/filtering-undefined-elements-from-array-typescript/) which makes use of user-defined type guards with `.filter()`.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/typescript-user-defined-type-guards-rescue</link>
            <guid isPermaLink="false">typescript-user-defined-type-guards-rescue</guid>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[narrowing]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 05 Dec 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[React Testing Library best practices]]></title>
            <description><![CDATA[
In my opinion, [ESLint](https://eslint.org/) is one of the best ways to communicate best practices for JavaScript code because it doesn't require everyone to read and follow a document or blog post. Instead it notifies the individual developer that they have broken a rule. A rule which itself typically has docs explaining the rule and how to fix it. **So without intervention from a senior developer or "expert", ESLint is able to communicate best practices.** And if the best practices change, the ESLint rules is updated, a new version of the plugin is released, and the offending code starts failing.

I've been using [React Testing Library](https://testing-library.com/docs/react-testing-library/) for several years now. After using [Enzyme](https://enzymejs.github.io/enzyme/) for many years prior, I found RTL to be a much better approach to testing React applications. Read [React Testing Library over Enzyme](/blog/react-testing-library-over-enzyme/) for more of my thoughts on the differences if you're interested. Although I've been using React Testing Library for a while, I only started recently using [`eslint-plugin-testing-library`](https://github.com/testing-library/eslint-plugin-testing-library). It codifies a whole bunch of best practices. Some of which had changed from when I had first learned RTL.

So I want to walk through 5 groups of those best practices to help us write healthier and more resilient React tests.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/react-testing-library-best-practices</link>
            <guid isPermaLink="false">react-testing-library-best-practices</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[testing]]></category>
            <category><![CDATA[eslint]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 21 Nov 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[TypeScript React props: interfaces vs type aliases]]></title>
            <description><![CDATA[
The first lesson in my [TypeScript for React Developers minishop](/minishops/typescript-for-react-developers/) is how to define the type of the `props` object passed to React component functions. And usually there will be someone who's already dabbled in TypeScript who asks me why I choose to use an `interface` instead of a `type` alias for defining the props. The short answer is that **interfaces and type alias are effectively interchangeable for defining objects in TypeScript.**

My assumption is that interfaces and type aliases used to have more differences between them, but as TypeScript has evolved they've both received upgrades to the point where they are now seemingly identical. The original TypeScript docs [suggested using an `interface`](https://www.typescriptlang.org/docs/handbook/advanced-types.html#interfaces-vs-type-aliases) over a `type` alias when possible, so that's what I've always done. But there are some nuances when one may make sense over the other. Instead of focusing on the technical differences, I want to spend this post focusing on the practical times we would use one over the other.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/typescript-react-props-interfaces-type-aliases</link>
            <guid isPermaLink="false">typescript-react-props-interfaces-type-aliases</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[props]]></category>
            <category><![CDATA[interface]]></category>
            <category><![CDATA[type]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 14 Nov 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Wrapping next/link to use with a custom UI Link component]]></title>
            <description><![CDATA[
[Next.js](https://nextjs.org/) has a pretty snazzy file-system based [router](https://nextjs.org/docs/routing/introduction) that is built on the concept of [pages](https://nextjs.org/docs/basic-features/pages). The router allows us to do client-side route transitions between pages similar to a single-page application (aka SPA). Next exports a React component called [`Link`](https://nextjs.org/docs/api-reference/next/link) to automatically handle these client-side route transitions.

```js
import Link from 'next/link'

const Home = () => {
  return (
    <ul>
      <li>
        <Link href="/">
          <a>Home</a>
        </Link>
      </li>
      <li>
        <Link href="/about">
          <a>About Us</a>
        </Link>
      </li>
      <li>
        <Link href="/blog/hello-world">
          <a>Blog Post</a>
        </Link>
      </li>
    </ul>
  )
}

export default Home
```

**But the Next `<Link>` renders a vanilla `<a>` tag with no styling**, which pretty much no one is going to want. We may throw a `className` on the `<a>` for styling, but more than likely we have a custom `<Link>` component of our own that handles the styling. I use the fantastic [MUI](https://mui.com/) React component library for my personal projects, and it has its own [`Link` component](https://mui.com/components/links/). So with MUI, the example becomes:

```js {8,13,18}
import NextLink from 'next/link'
import { Link as MuiLink } from '@mui/material'

const Home = () => {
  return (
    <ul>
      <li>
        <NextLink href="/" passHref>
          <MuiLink>Home</MuiLink>
        </NextLink>
      </li>
      <li>
        <NextLink href="/about" passHref>
          <MuiLink>About Us</MuiLink>
        </NextLink>
      </li>
      <li>
        <NextLink href="/blog/hello-world" passHref>
          <MuiLink>Blog Post</MuiLink>
        </NextLink>
      </li>
    </ul>
  )
}

export default Home
```

Notice that we had to add the [`passHref`](https://nextjs.org/docs/api-reference/next/link#if-the-child-is-a-custom-component-that-wraps-an-a-tag) prop to the `<NextLink>` so that the `href` is passed down to the `<MuiLink>`. Otherwise we'd have to duplicate the `href` prop on both the `<NextLink>` and the `<MuiLink>` components.

> It's important to note that if your component library's `Link` component is a function component (more than likely it is given Hooks), it must wrap the component in [`React.forwardRef`](https://reactjs.org/docs/forwarding-refs.html).

**But having to do this double `<Link>` dance every time we want to render a styled link gets annoying**, especially if we're passing more props to the `<NextLink>` and `<MuiLink>`. So what I typically do in my Next apps is create a lightweight custom `Link` component that wraps both `next/link` and MUI `Link`.

```js
import { forwardRef } from 'react'
import NextLink from 'next/link'
import { Link as MuiLink } from '@mui/material'

/**
 * A convenience component that wraps the MUI `Link` component that provides
 * our look & feel with Next's router `Link`
 *
 * @see https://next.js.org/docs/api-reference/next/link
 */
const Link = forwardRef(function Link(
  { href, prefetch, replace, scroll, shallow, locale, ...muiProps },
  ref,
) {
  return (
    <NextLink
      href={href}
      replace={replace}
      scroll={scroll}
      shallow={shallow}
      locale={locale}
      passHref
    >
      <MuiLink ref={ref} {...muiProps} />
    </NextLink>
  )
})

export default Link
```

The component isn't terribly complex. It takes in the props and passes the appropriate ones to the underlying `<NextLink>` versus the `<MuiLink>`. Because it's a function component, it also uses [`forwardRef`](https://reactjs.org/docs/forwarding-refs.html) so that it can still support refs like the underlying `<MuiLink>`.

> I use a function declaration (`function Link`) instead of my typical arrow function so that the component definition within `forwardRef` still has a component name (`Link`). It helps with debugging in the DevTools so that it'll say `ForwardRef(Link)` instead of just `ForwardRef`.

But since I develop in React with TypeScript, my `Link` component actually looks like this:

```tsx {7-8,16}
import { forwardRef } from 'react'
import NextLink, { LinkProps as NextLinkProps } from 'next/link'
import { Link as MuiLink, LinkProps as MuiLinkProps } from '@mui/material'

// `LinkProps` is the combination of the MUI `LinkProps` and the Next `LinkProps`
// We wanna use the `href` prop from `next/link` so we omit it from MUI's.
export type LinkProps = Omit<MuiLinkProps, 'href'> &
  Omit<NextLinkProps, 'as' | 'passHref' | 'children'>

/**
 * A convenience component that wraps the MUI `Link` component that provides
 * our look & feel with Next's router `Link`
 *
 * @see https://next.js.org/docs/api-reference/next/link
 */
const Link = forwardRef<HTMLAnchorElement, LinkProps>(function Link(
  { href, prefetch, replace, scroll, shallow, locale, ...muiProps },
  ref,
) {
  return (
    <NextLink
      href={href}
      replace={replace}
      scroll={scroll}
      shallow={shallow}
      locale={locale}
      passHref
    >
      <MuiLink ref={ref} {...muiProps} />
    </NextLink>
  )
})

export default Link
```

The main difference here is the `LinkProps` type definition.

```typescript
type LinkProps = Omit<MuiLinkProps, 'href'> &
  Omit<NextLinkProps, 'as' | 'passHref' | 'children'>
```

**It ensures that we only can pass in valid props for our new `<Link>` component.** How it's defined is also important. First we take all the props of our component library's `Link` component (`MuiLinkProps` in this case), but omits the `href` prop. This is because it is also defined in `NextLinkProps` and we want to ensure that we use the type definition for `href` from `next/link` because it supports both a `string` as well as a [`URL` object](https://nodejs.org/api/url.html#url_url_strings_and_url_objects).

Then we intersect (or extend) all of the props from `NextLinkProps`. I personally also exclude the [`as`](https://nextjs.org/docs/tag/v9.5.2/api-reference/next/link#dynamic-routes) prop because it's basically legacy functionality. We can omit `passHref` and `children` as well because we're explicitly setting them on `<NextLink>` (the `children` of `<NextLink>` is the `<MuiLink>`).

Lastly, we update `forwardRef()` to include the ref type and component props type as the generic params: `forwardRef<HTMLAnchorElement, LinkProps>`.

So now back in our home page component, we can use our new `<Link>` component.

```js {7,10,13}
import Link from '../components/Link'

const Home = () => {
  return (
    <ul>
      <li>
        <Link href="/">Home</Link>
      </li>
      <li>
        <Link href="/about">About Us</Link>
      </li>
      <li>
        <Link href="/blog/hello-world">Blog Post</Link>
      </li>
    </ul>
  )
}

export default Home
```

Now we're back to it _feeling_ like we're just using our component library `<Link>` component, but with all of the bells and whistles of `next/link`. 🎉

One more thing before we finish. The `next/link` only works for local links. It does nothing for external links. **In fact, using it for external links results in a bunch of wasted work.** So it's better if we just use our component library's `<Link>` component directly.

```js {17}
import { Link as ExternalLink } from '@mui/material'
import Link from '../components/Link'

const Home = () => {
  return (
    <ul>
      <li>
        <Link href="/">Home</Link>
      </li>
      <li>
        <Link href="/about">About Us</Link>
      </li>
      <li>
        <Link href="/blog/hello-world">Blog Post</Link>
      </li>
      <li>
        <ExternalLink href="https://www.benmvp.com">Ben Ilegbodu</ExternalLink>
      </li>
    </ul>
  )
}

export default Home
```

I explicitly name the component library's link component `ExternalLink` to make it abundantly clear that it's only to be used for external links. Our custom `<Link>` component that wraps `next/link` is the default one to use.

Alternatively, I could update the custom `Link` component to be smarter and only render a `<MuiLink>` when the url is external, but then it would need all the logic to resolve the `href` to a `string` if it's a `URL` object and then detect whether or not a URL string is external. That's more work than I'm willing to put in. 😅

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/wrapping-next-link-custom-ui-link-component</link>
            <guid isPermaLink="false">wrapping-next-link-custom-ui-link-component</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[nextjs]]></category>
            <category><![CDATA[link]]></category>
            <category><![CDATA[component]]></category>
            <category><![CDATA[routing]]></category>
            <category><![CDATA[router]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 07 Nov 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[What is a DivOps Engineer and what do they do?]]></title>
            <description><![CDATA[
I've written a number of _DivOps_-focused posts ([5 tips for a healthier DivOps setup](/blog/5-tips-healthier-divops-setup/), [50 shades of React rendering with Next.js](/blog/50-shades-react-rendering-nextjs/), and [Auto-generate React PropTypes from TypeScript components](/blog/auto-generate-react-prop-types-typescript-components/) just to name a few). But I've never actually explained what _DivOps_ is. It's a play on words for [DevOps](https://www.atlassian.com/devops) which is a well-defined role bridging the gap between software development and IT operations.

DivOps to me is the bridge between frontend web development and traditional DevOps. **So a DivOps engineer writes code for web frontend applications and libraries, but rarely is any of it shipped to Production or what users interact with.** Instead they write all of the tooling and configuration code _outside_ of the `src` folder that's needed for an app or lib to run.

Although I write a lot about DivOps, I can't take full credit for the term. [Enrique](https://twitter.com/chochosmx) coined the term with this tweet:

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Frontend engineers who also manage infra should be called &lt;div&gt;ops</p>&mdash; Enrique staying ~ (@chochosmx) <a href="https://twitter.com/chochosmx/status/1183045782095699968?ref_src=twsrc%5Etfw">October 12, 2019</a></blockquote>

And my friend [Jonathan Creamer](https://twitter.com/jcreamer898) made it "official" by [creating the #DivOps community](https://www.jonathancreamer.com/announcing-div-ops/). Check out the [r/divops](https://www.reddit.com/r/divops/) subreddit and [DivOps Discord server](https://discord.gg/Vvk67JDX6t) to join the community.

I have yet to see an explicit role for a "DivOps Engineer," but I think we're getting close. **Typically those fulfilling the role are Frontend Engineers working on the frontend platform (possibly even on a Frontend Platform team), but are not working on the design system or component library.** These developers are likely focused on DivOps.

I would like to see companies create explicit roles for this work because it's highly valuable and critical. In my opinion, formalizing the role legitimizes the work and provides a 3rd path in frontend engineering. In addition to UI development (visual + interaction) or app development (state + API management), there's now DivOps.

So I want to list out the high-level areas of work to which a DivOps engineer contributes, as well as some of the tooling within each area.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/what-divops-engineer</link>
            <guid isPermaLink="false">what-divops-engineer</guid>
            <category><![CDATA[divops]]></category>
            <category><![CDATA[engineer]]></category>
            <category><![CDATA[frontend]]></category>
            <category><![CDATA[tooling]]></category>
            <category><![CDATA[platform]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 31 Oct 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Learn TypeScript generics by rebuilding existing utility types]]></title>
            <description><![CDATA[
TypeScript's type system is very powerful because it allows us to express types in terms of other types. One way we do this is with [generics](https://www.typescriptlang.org/docs/handbook/2/generics.html), which are types that take parameters. A lot of times when we get started with generics, we actually use them directly within functions (see my previous post on [Understanding TypeScript generics through lodash functions](https://www.benmvp.com/blog/understanding-typescript-generics-lodash-functions/)). But when we use them to create reusable types, we can create really powerful types much like the built-in [utility types](https://www.typescriptlang.org/docs/handbook/utility-types.html).

So I want to break down some existing TypeScript utilty types in order for us to better understand how TypeScript generics work. I personally learn best by seeing real-world examples. Somehow seeing something new in the context of something familiar helps me make the connection. I hoping it'll do the same for you.

Without further ado, let's dig in.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/learn-typescript-generics-rebuilding-existing-utility-types</link>
            <guid isPermaLink="false">learn-typescript-generics-rebuilding-existing-utility-types</guid>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[generics]]></category>
            <category><![CDATA[utilities]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 24 Oct 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[How to extract React component logic into a custom Hook]]></title>
            <description><![CDATA[
[React custom Hooks](https://reactjs.org/docs/hooks-custom.html) are kind of like logic helpers for our React components, so that the components themselves can focus on rendering and user interactions. Commonly folks will extract component logic into a custom Hook when they need to reuse the logic in multiple components (such as [`useMedia`](https://github.com/streamich/react-use/blob/master/docs/useMedia.md), [`useClickAway`](https://github.com/streamich/react-use/blob/master/docs/useClickAway.md), [`useEffectOnce`](https://github.com/streamich/react-use/blob/master/docs/useEffectOnce.md), and [many others](https://github.com/streamich/react-use)). But I will also make a single-use custom Hook simply when the logic is large or complex. In my opinion, it makes it easier to reason about the logic and UI separately.

Let's say we have a hypothetical page that has a list of teams and a list of players. And at the top it has filters for both the teams and players.

```js
import { useEffect, useState } from 'react'

const Page = () => {
  const [teamsFilter, setTeamFilter] = useState('')
  const [teams, setTeams] = useState([])
  const [playersFilter, setPlayersFilter] = useState('')
  const [players, setPlayers] = useState([])

  useEffect(() => {
    // page is mounted once `useEffect()` is called
    let isMounted = true

    window
      .fetch(`https://api.benmvp.com/teams?q=${teamsFilter}`)
      .then((res) => res.json())
      .then((data) => {
        // only set state if page is still mounted
        if (isMounted) {
          setTeams(data.teams)
        }
      })

    window
      .fetch(`https://api.benmvp.com/players?q=${playersFilter}`)
      .then((res) => res.json())
      .then((data) => {
        // only set state if page is still mounted
        if (isMounted) {
          setPlayers(data.players)
        }
      })

    return () => {
      // page is no longer mounted when cleanup func is called
      isMounted = false
    }
    // makes both API calls when either filter changes 👎🏾
  }, [teamsFilter, playersFilter])

  return (
    <div>
      <TeamsFilter filter={teamsFilter} onChange={setTeamFilter} />
      <PlayersFilter filter={playersFilter} onChange={setPlayersFilter} />

      <Teams teams={teams} />
      <Players players={players} teams={teams} />
    </div>
  )
}
```

> If you're wondering about the `isMounted` check after we receive the data from the API, it's to ensure that the component wasn't unmounted during the time that we made the API request and got back the response. Read [Handling async React component effects after unmount](/blog/handling-async-react-component-effects-after-unmount/) for more details on the problem and solution.

The component makes two API requests any time the `TeamsFilter` or `PlayersFilter` change. But it's inefficient because only one filter can change at a time, yet we make requests to both APIs. So if we're changing the `TeamsFilter` we're still retrieving the same `players` data over and over. We can fix by splitting up the single `useEffect()` call into two of them.

```js
import { useEffect, useState } from 'react'

const Page = () => {
  const [teamsFilter, setTeamFilter] = useState('')
  const [teams, setTeams] = useState([])
  const [playersFilter, setPlayersFilter] = useState('')
  const [players, setPlayers] = useState([])

  // separate the teams `useEffect()` from the players one so that
  // we only retrieve data for the one that has changed

  useEffect(() => {
    let isMounted = true

    window
      .fetch(`https://api.benmvp.com/teams?q=${teamsFilter}`)
      .then((res) => res.json())
      .then((data) => {
        if (isMounted) {
          setTeams(data.teams)
        }
      })

    return () => {
      isMounted = false
    }
  }, [teamsFilter])

  useEffect(() => {
    let isMounted = true

    window
      .fetch(`https://api.benmvp.com/players?q=${playersFilter}`)
      .then((res) => res.json())
      .then((data) => {
        if (isMounted) {
          setPlayers(data.players)
        }
      })

    return () => {
      isMounted = false
    }
  }, [playersFilter])

  return (
    <div>
      <TeamsFilter filter={teamsFilter} onChange={setTeamFilter} />
      <PlayersFilter filter={playersFilter} onChange={setPlayersFilter} />

      <Teams teams={teams} />
      <Players players={players} teams={teams} />
    </div>
  )
}
```

As you can see the component is dominated by what I call the component logic. This is all the state management code: the state itself (`teams` & `players`), the API calls and updating the state (`setTeams` & `setPlayers`). So what I would probably do now is break out the teams state management code and the players state management code into their own [custom React Hooks](https://reactjs.org/docs/hooks-custom.html).

```js
import { useEffect, useState } from 'react'

// Take a filter and return the teams when we
// get the data
const useTeams = (filter = '') => {
  const [teams, setTeams] = useState([])

  useEffect(() => {
    let isMounted = true

    window
      .fetch(`https://api.benmvp.com/teams?q=${filter}`)
      .then((res) => res.json())
      .then((data) => {
        if (isMounted) {
          setTeams(data.teams)
        }
      })

    return () => {
      isMounted = false
    }
  }, [filter])

  // at first `teams` will be `[]` but after the API
  // response, it'll return again with the API data
  // (provided the component is still mounted)

  return teams
}

// Take a filter and return the players when we
// get the data
const usePlayers = (filter = '') => {
  const [players, setPlayers] = useState([])

  useEffect(() => {
    let isMounted = true

    window
      .fetch(`https://api.benmvp.com/players?q=${filter}`)
      .then((res) => res.json())
      .then((data) => {
        if (isMounted) {
          setPlayers(data.players)
        }
      })

    return () => {
      isMounted = false
    }
  }, [filter])

  // at first `teams` will be `[]` but after the API
  // response, it'll return again with the API data
  // (provided the component is still mounted)

  return players
}

const Page = () => {
  const [teamsFilter, setTeamFilter] = useState('')
  const [playersFilter, setPlayersFilter] = useState('')
  const teams = useTeams(teamsFilter)
  const players = usePlayers(playersFilter)

  return (
    <div>
      <TeamsFilter filter={teamsFilter} onChange={setTeamFilter} />
      <PlayersFilter filter={playersFilter} onChange={setPlayersFilter} />

      <Teams teams={teams} />
      <Players players={players} teams={teams} />
    </div>
  )
}
```

Overall the code is a bit longer than it was before, but I would argue that it is easier to reason about now that the component logic is split out into the `useTeams()` and `usePlayers()` custom Hooks. We can think of custom Hooks in much the same way we thinking about regular JavaScript helper/utility functions that extract logic. The unique aspect about custom Hooks is that they can call other Hooks. And when the state within the custom Hook updates, the component that calls the Hook also is re-rendered in order to retrieve the new data!

Now instead of the `Page` component maintaining the `teams` and `players` states directly, it gets them `useTeams()` and `usePlayers()`, respectively. The `useTeams()` and `usePlayers()` custom Hooks are only being used once, but I extracted them just to "clean up" the component. What it's responsible for now is greatly simplified. In my opinion, it's much easier to follow what's happen in `Page`.

The extraction also allows me to now zero in on the logic of the Hooks themselves. There are still some commonalities between `useTeams()` and `usePlayers()`. They both make API calls, and they both check the mounted state before setting the state. Let's try extracting _that_ logic into a `useFetch()` custom Hook.

```js
import { useEffect, useState } from 'react'

// given a url fetch the data and return the JSON
// response, provided that the component is still
// mounted
const useFetch = (url) => {
  const [jsonData, setJsonData] = useState(undefined)

  useEffect(() => {
    let isMounted = true

    window
      .fetch(url)
      .then((res) => res.json())
      .then((data) => {
        if (isMounted) {
          setJsonData(data)
        }
      })

    return () => {
      isMounted = false
    }
  }, [url])

  // at first `jsonData` will be `undefined but after the API
  // response, it'll return again with the API data
  // (provided the component is still mounted)

  return jsonData
}

const useTeams = (filter = '') => {
  const data = useFetch(`https://api.benmvp.com/teams?q=${filter}`)

  // if `data` or `data.teams` is `undefined` return `[]`
  return data?.teams ?? []
}

const usePlayers = (filter = '') => {
  const data = useFetch(`https://api.benmvp.com/players?q=${filter}`)

  // if `data` or `data.players` is `undefined` return `[]`
  return data?.players ?? []
}

const Page = () => {
  const [teamsFilter, setTeamFilter] = useState('')
  const [playersFilter, setPlayersFilter] = useState('')
  const teams = useTeams(teamsFilter)
  const players = usePlayers(playersFilter)

  return (
    <div>
      <TeamsFilter filter={teamsFilter} onChange={setTeamFilter} />
      <PlayersFilter filter={playersFilter} onChange={setPlayersFilter} />

      <Teams teams={teams} />
      <Players players={players} teams={teams} />
    </div>
  )
}
```

> If the [`?.` (optional chaining)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining) or [`??` (nullish coalescing)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator) operators are new to you, check out my [Using new-ish & lesser-known JavaScript operators to write concise code](/blog/using-javascript-operators-write-concise-code/) post that explains them and other cool operators you might not yet know (but totally should).

Now the `useTeams()` and `usePlayers()` custom Hooks have been hollowed out. Their `data` is initially `undefined` prior to the API request in `useFetch()`. And then when `useFetch()` gets back the JSON data, it'll set it only if the `useEffect()` hasn't been cleaned up. As a result of the state update in `useFetch()`, the `useTeams()` or `usePlayers()` Hooks re-run to get the new `data` which will be returned back to the `Page` component.

And now that we have a rather generic `useFetch()` helper we can add more functionality to it (like having a loading state or error handling) without adding complexity to the `Page` component or even the `useTeams()` and `usePlayers()` custom Hooks. That's the power of React custom Hooks.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/how-to-extract-react-component-logic-custom-hook</link>
            <guid isPermaLink="false">how-to-extract-react-component-logic-custom-hook</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[hooks]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 17 Oct 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[React useCallback & useMemo use cases]]></title>
            <description><![CDATA[
I went a long while writing React with Hooks without using the [`useCallback()`](https://reactjs.org/docs/hooks-reference.html#usecallback) or [`useMemo()`](https://reactjs.org/docs/hooks-reference.html#usememo) Hooks. And even now I still hardly use `useMemo()`. So that's all to say that we can build perfectly fine React applications without knowing or using either Hook.

However, I'm frequently asked to explain when and why we would use `useCallback()` or `useMemo()` so I figured I might as well take some time to explain when I use them most frequently. Pretty much it comes down to maintaining [referential (strict) equality](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness) in the dependencies of Hooks, or avoiding recalculating expensive computations.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/react-usecallback-usememo-use-cases</link>
            <guid isPermaLink="false">react-usecallback-usememo-use-cases</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[hooks]]></category>
            <category><![CDATA[usecallback]]></category>
            <category><![CDATA[useMemo]]></category>
            <category><![CDATA[performance]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 10 Oct 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Successfully using async functions in React useEffect]]></title>
            <description><![CDATA[
JavaScript [async functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) making dealing with [promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) a bit simpler because it flattens out nested promises into sequential statements. But using async functions within React's [`useEffect()`](https://reactjs.org/docs/hooks-effect.html) comes with a gotcha that I'd like to walk through and explain.

Let's say we have a `useTopPlayers()` custom Hook that retrieves the NBA best players in a specific statistical category. The NBA's "API" only returns the IDs of the players, so after getting the IDs we have to make **another** API request to get the raw player info for each. Finally we need to normalize the raw info into a useful format that our app can consume.

```js
import { useEffect, useState } from 'react'
import Bugsnag from '@bugsnag/js'
import {
  getTopPlayers as getTopPlayersApi,
  getPlayersById as getPlayersByIdApi,
} from './api'
import { normalizeApiPlayers } from './utils'

const useTopPlayers = (category, season) => {
  const [players, setPlayers] = useState([])

  useEffect(() => {
    getTopPlayersApi(category, season)
      .then((playerIds) => {
        // avoid nesting by returning the promise returned by
        // `getPlayersByIdApi`
        return getPlayersByIdApi(playerIds)
      })
      .then((rawPlayers) => {
        setPlayers(normalizeApiPlayers(rawPlayers))
      })
      .catch((err) => {
        // notify our error monitoring (using Bugsnag)
        Bugsnag.notify(err)

        // `null` players means an error happened
        setPlayers(null)
      })
  }, [category, season])

  return players
}
```

This is pretty standard code. It's simplified a bit because I have abstracted the logic around making the two API requests and normalizing the data into helper functions. But there are two main drawbacks of using promises here:

1. Any code depending on the result of the call to `getTopPlayersApi()` has to be nested within the `.then()` promise chain.
2. Another async call within a `.then()` could result in nested promise chains which is basically the same as [callback hell](http://callbackhell.com/). We can at least flatten the chain by returning the promise returned by the nested async function in the outer `.then()`.

Async functions to the rescue! The naive approach would be to add [`async`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) to `useEffect()`'s callback function.

```js {5,7-8}
const useTopPlayers = (category, season) => {
  const [players, setPlayers] = useState([])

  // 🛑 DON'T DO THIS! 🛑
  useEffect(async () => {
    try {
      const playerIds = await getTopPlayersApi(category, season)
      const rawPlayers = await getPlayersByIdApi(playerIds)

      setPlayers(normalizeApiPlayers(rawPlayers))
    } catch (err) {
      Bugsnag.notify(err)
      setPlayers(null)
    }
  }, [category, season])

  return players
}
```

The code seems to flow more nicely using [`await`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await), right? But we're unintentionally breaking one of the rules of the `useEffect()` Hook by making `useEffect()` asynchronous.

Despite breaking the rules, the majority of the time our code would still work fine. **However, if we have multiple `useEffect()` calls that were order-dependent, we could run into a race-condition, creating a bug that would be super hard to track down.** But if we're using the [React Hooks ESLint Plugin](https://www.npmjs.com/package/eslint-plugin-react-hooks) (which we absolutely should be), it clues us in to our lurking issue.

```
Effect callbacks are synchronous to prevent race conditions. Put the async function inside:

useEffect(() => {
  async function fetchData() {
    // You can await here
    const response = await MyAPI.getData(someId);
    // ...
  }
  fetchData();
}, [someId]); // Or [] if effect doesn't need props or state

Learn more about data fetching with Hooks: https://reactjs.org/link/hooks-data-fetchingeslintreact-hooks/exhaustive-deps
```

Similarly, if we're using TypeScript it also warns us of the problem (although admittedly far less clearly).

```
Argument of type '() => Promise<void>' is not assignable to parameter of type 'EffectCallback'.
  Type 'Promise<void>' is not assignable to type 'void | Destructor'.
    Type 'Promise<void>' is not assignable to type 'Destructor'.
      Type 'Promise<void>' provides no match for the signature '(): void | { [UNDEFINED_VOID_ONLY]: never; }'.
```

What are these errors telling us? Well, `useEffect()` is supposed to either return nothing or a [cleanup function](https://reactjs.org/docs/hooks-effect.html#example-using-hooks-1). But by making the `useEffect()` function an async function, it [automatically returns a `Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function#return_value) (even if that promise contains no data).

You may be tempted, instead, to move the `async` to the function containing the `useEffect()` (i.e. the custom Hook).

```js {2}
// 🛑 DON'T DO THIS! 🛑
const useTopPlayers = async (category, season) => {
  const [players, setPlayers] = useState([])

  useEffect(() => {
    try {
      const playerIds = await getTopPlayersApi(category, season)
      const rawPlayers = await getPlayersByIdApi(playerIds)

      setPlayers(normalizeApiPlayers(rawPlayers))
    } catch (err) {
      Bugsnag.notify(err)
      setPlayers(null)
    }
  }, [category, season])

  return players
}
```

But this doesn't work at all for 2 main reasons. First, by making the custom Hook `async`, we're now returning `players` data wrapped in a `Promise` instead of just `players`. Remember, `async` automatically makes the function return a `Promise`. Secondly, `await` only works if its _direct_ containing function is `async`. **You cannot put `async` on a top-level function and expect `await` to work within nested functions.** So it not only doesn't work with React, but also isn't even valid JavaScript.

Instead, we can follow the lint error's suggestion by defining an `async` inner function within the `useEffect()` function and immediately calling it.

```js {6,8-9,19}
const useTopPlayers = (category, season) => {
  const [players, setPlayers] = useState([])

  useEffect(() => {
    // Add inner async function
    const fetchTopPlayers = async () => {
      try {
        const playerIds = await getTopPlayersApi(category, season)
        const rawPlayers = await getPlayersByIdApi(playerIds)

        setPlayers(normalizeApiPlayers(rawPlayers))
      } catch (err) {
        Bugsnag.notify(err)
        setPlayers(null)
      }
    }

    // Call function immediately
    fetchTopPlayers()
  }, [category, season])

  return players
}
```

Now the Hook is back to returning `players` data and the main `useEffect()` function is back to returning nothing. Instead, we've defined the `fetchTopPlayers()` inner function that we immediately call. We make `fetchTopPlayers()` an async function so that we can use `await` within it.

I gotta admit, having to define the inner function is a bit clunky. But, in my opinion, it's a small price to pay to drastically improve the developer experience of async `useEffect` calls. You know, what's actually the most annoying is having to come up with a non-duplicative name for the inner function. We _could_ instead use an [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) (immediately-invoked function expression).

```js {6,16}
const useTopPlayers = (category, season) => {
  const [players, setPlayers] = useState([])

  useEffect(() => {
    // use IIFE to avoid creating named function 🤪
    ;(async () => {
      try {
        const playerIds = await getTopPlayersApi(category, season)
        const rawPlayers = await getPlayersByIdApi(playerIds)

        setPlayers(normalizeApiPlayers(rawPlayers))
      } catch (err) {
        Bugsnag.notify(err)
        setPlayers(null)
      }
    })()
  }, [category, season])

  return players
}
```

> [Prettier](https://prettier.io/) automatically adds that weird `;` at the beginning of the statement. Because I don't normally use semicolons in my code, if there was a line prior to the IIFE the JavaScript interpreter wouldn't be able to properly understand what's going on.

But to me, this is taking a clunky solution and making it worse. 🤪

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/successfully-using-async-functions-useeffect-react</link>
            <guid isPermaLink="false">successfully-using-async-functions-useeffect-react</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[hooks]]></category>
            <category><![CDATA[async]]></category>
            <category><![CDATA[functions]]></category>
            <category><![CDATA[linting]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 26 Sep 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Using new-ish & lesser-known JavaScript operators to write concise code]]></title>
            <description><![CDATA[
JavaScript has been around for over 25 years, since May 1995 when [Brendan Eich](http://en.wikipedia.org/wiki/Brendan_Eich) supposedly created it in 10 days. I wrote a full [history of ECMAScript](/blog/learning-es6-history-of-ecmascript/) if you're interested in learning more. There's a lot of syntax and operators that has been added to JavaScript since its inception. Many we use regularly (like `===`, `&&`, etc.) so they are familiar to us, but there are others that are rarely used, but still have some useful use cases.

So I want to walk through 8 operators that are either new(-ish) or lesser-known, and explain the situations in which we may want to use them to make our code more concise and/or accurate. Let's jump right in!

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/using-javascript-operators-write-concise-code</link>
            <guid isPermaLink="false">using-javascript-operators-write-concise-code</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[operators]]></category>
            <category><![CDATA[ecmascript]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 19 Sep 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[How to create an SVG gradient loading spinner]]></title>
            <description><![CDATA[
I recently got to work on a different type of project than I normally tackle. Instead of building a React component in TypeScript or configuring a new DivOps setup, I needed to create an SVG gradient loading spinner. It looked like:

<Image src="loading-spinner-final.svg" alt="SVG loading spinner with a gradient fill" style={{ display: 'block', margin: '0 auto 16px' }} />

The spinner isn't a solid color, but has a gradient from 100% to 0% opacity. The design seemed simple enough, but the implementation ended up being way more complicated than I anticipated. This is because **SVGs don't support adding a gradient to a [`<circle>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/circle).** However, it's possible to simulate a gradient with some cleverness.

If you just need an answer so you can move on to solve your problem, here's my final solution. 😄

```html
<svg
  width="200"
  height="200"
  viewBox="0 0 200 200"
  color="#3f51b5"
  fill="none"
  xmlns="http://www.w3.org/2000/svg"
>
  <defs>
    <linearGradient id="spinner-secondHalf">
      <stop offset="0%" stop-opacity="0" stop-color="currentColor" />
      <stop offset="100%" stop-opacity="0.5" stop-color="currentColor" />
    </linearGradient>
    <linearGradient id="spinner-firstHalf">
      <stop offset="0%" stop-opacity="1" stop-color="currentColor" />
      <stop offset="100%" stop-opacity="0.5" stop-color="currentColor" />
    </linearGradient>
  </defs>

  <g stroke-width="8">
    <path stroke="url(#spinner-secondHalf)" d="M 4 100 A 96 96 0 0 1 196 100" />
    <path stroke="url(#spinner-firstHalf)" d="M 196 100 A 96 96 0 0 1 4 100" />

    <!-- 1deg extra path to have the round end cap -->
    <path
      stroke="currentColor"
      stroke-linecap="round"
      d="M 4 100 A 96 96 0 0 1 4 98"
    />
  </g>

  <animateTransform
    from="0 0 0"
    to="360 0 0"
    attributeName="transform"
    type="rotate"
    repeatCount="indefinite"
    dur="1300ms"
  />
</svg>
```

If you're interested in learning about SVGs or how I was able to piece together tidbits from different sources of information to solve the problem, I would love to walk you through my journey. It's my journey in how I learned how to add a gradient along an SVG circular path so that I could create this loading spinner.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/how-to-create-circle-svg-gradient-loading-spinner</link>
            <guid isPermaLink="false">how-to-create-circle-svg-gradient-loading-spinner</guid>
            <category><![CDATA[svg]]></category>
            <category><![CDATA[animations]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 12 Sep 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[How to shallow clone a JavaScript array]]></title>
            <description><![CDATA[
Usually the rationale for shallow cloning an array is because we want to mutate it, but we need to leave the original unchanged. This practice of "defensive programming" is common in utility functions because we don't know if the caller will need to use the array for other purposes. **Mutating the array directly can cause hard-to-catch bugs.** So we copy it first, and then perform whatever mutations are necessary.

To help ground this need in reality, let's apply shallow cloning an array in a real-world scenario. Let's say we have a helper function called `addMessge()` that will add a specified message to the list of messages with the current timestamp.

There are likely more, but I've got 8 approaches for creating a shallow copy of a JavaScript array. Let's dive right in!

> FYI: A shallow copy means that we do not make copies of deeply nested objects. So if an element of an array is an object, we only copy over its reference. We don't traverse the object creating new copies of each of its properties.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/how-to-shallow-clone-javascript-array</link>
            <guid isPermaLink="false">how-to-shallow-clone-javascript-array</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[arrays]]></category>
            <category><![CDATA[shallow]]></category>
            <category><![CDATA[clone]]></category>
            <category><![CDATA[copy]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 29 Aug 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Understanding TypeScript generics through lodash functions]]></title>
            <description><![CDATA[
JavaScript is a highly dynamic language, so generics are instrumental in helping us to add types to make our code type safe with TypeScript. [TypeScript Generics](https://www.typescriptlang.org/docs/handbook/2/generics.html) are super powerful, but also can be pretty complicated. As a result, we find lots of blog posts, YouTube videos, workshops, and courses on how to use generics in TypeScript.

This post is a little different. I learn best by seeing real-world examples. Seeing something new in the context of something familiar helps my brain make the connections. So this post walks through how we can develop with TypeScript generics (something new) by re-implementing common lodash functions (something familiar). My hope is that these examples will help build and solidify your understanding of how to leverage generics in your TypeScript code.

Let's get started!

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/understanding-typescript-generics-lodash-functions</link>
            <guid isPermaLink="false">understanding-typescript-generics-lodash-functions</guid>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[generics]]></category>
            <category><![CDATA[lodash]]></category>
            <category><![CDATA[arrays]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 22 Aug 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Forwarding refs for a polymorphic React component in TypeScript]]></title>
            <description><![CDATA[
Late last year I wrote about how to develop [Polymorphic React Components in TypeScript](/blog/polymorphic-react-components-typescript/). Polymorphic components are one of the [React component patterns](/blog/picking-right-react-component-pattern/) that enable us to create reusable and extendable components without having to rewrite display/layout, visual look-and-feel, and/or UI logic.

The implementation from that post, however, didn't discuss how to properly type a polymorphic component in TypeScript when it supports a ref using [`forwardRef()`](https://reactjs.org/docs/forwarding-refs.html). That was an additional wrinkle that my team needed and figured out later. So let's talk about it now.

Just so we're all on the same page, here's our polymorphic `Text` component in TypeScript (including the helper types):

```typescript
import React from 'react'

// Source: https://github.com/emotion-js/emotion/blob/master/packages/styled-base/types/helper.d.ts
// A more precise version of just React.ComponentPropsWithoutRef on its own
export type PropsOf<
  C extends keyof JSX.IntrinsicElements | React.JSXElementConstructor<any>
> = JSX.LibraryManagedAttributes<C, React.ComponentPropsWithoutRef<C>>

type AsProp<C extends React.ElementType> = {
  /**
   * An override of the default HTML tag.
   * Can also be another React component.
   */
  as?: C
}

/**
 * Allows for extending a set of props (`ExtendedProps`) by an overriding set of props
 * (`OverrideProps`), ensuring that any duplicates are overridden by the overriding
 * set of props.
 */
export type ExtendableProps<
  ExtendedProps = {},
  OverrideProps = {}
> = OverrideProps & Omit<ExtendedProps, keyof OverrideProps>

/**
 * Allows for inheriting the props from the specified element type so that
 * props like children, className & style work, as well as element-specific
 * attributes like aria roles. The component (`C`) must be passed in.
 */
export type InheritableElementProps<
  C extends React.ElementType,
  Props = {}
> = ExtendableProps<PropsOf<C>, Props>

/**
 * A more sophisticated version of `InheritableElementProps` where
 * the passed in `as` prop will determine which props can be included
 */
export type PolymorphicComponentProps<
  C extends React.ElementType,
  Props = {}
> = InheritableElementProps<C, Props & AsProp<C>>

// 👇🏾👇🏾 sample usage in `Text` component 👇🏾👇🏾

interface Props {
  children: React.ReactNode
  color?: Color
  font?: 'thin' | 'regular' | 'heavy'
  size?: '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10'
}

type TextProps<C extends React.ElementType> = PolymorphicComponentProps<
  C,
  Props
>

export const Text = <C extends React.ElementType = 'span'>({
  as,
  children,
  font = 'regular',
  size = '4',
  color = 'gray-40',
  ...other
}: TextProps<C>) => {
  const classes = getClasses({ font, size, color })
  const Component = as || 'span'

  return (
    <Component {...other} className={classes}>
      {children}
    </Component>
  )
}
```

> If you're not quite sure how all of this works, read [Polymorphic React Components in TypeScript](/blog/polymorphic-react-components-typescript/) first for a step-by-step explanation.

When using [`forwardRef()` generic function in TypeScript](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/2dfb801ec978b29ab81690a9b24ecb1f06c4eaf2/types/react/index.d.ts#L804) with a non polymorphic component, we pass in the type of the ref with the function call. Let's pretend our `Text` component is a simple component that always renders a `<span>`, so the type of the `ref` is `HTMLSpanElement`.

```typescript {1,6}
export const Text = React.forwardRef<HTMLSpanElement, TextProps>(
  ({ children, font = 'regular', size = '4', color = 'gray-40' }, ref) => {
    const classes = getClasses({ font, size, color })

    return (
      <span ref={ref} className={classes}>
        {children}
      </span>
    )
  },
)
```

When defining a polymorphic component, we need to replace `HTMLSpanElement` with our `C` generic type, but we can't. **The problem is that `forwardRef()` is a function call so there's no opportunity to define the generic `C` type to pass to it.** We could wrap `forwardRef()` in a function call, a component generator of sorts. But then we would no longer have the component interface and couldn't use JSX directly.

So here's what we came up with.

First we defined a new helper type, `PolymorphicRef`, that returns the type of the ref for the polymorphic component.

```typescript
export type PolymorphicRef<
  C extends React.ElementType
> = React.ComponentPropsWithRef<C>['ref']
```

We can then use this type in our call to `forwardRef()` to avoid passing in the types to the function call. Instead we declare the types of the individual function parameters.

```typescript
// highlight-range{10-11,17}
export const Text = React.forwardRef(
  <C extends React.ElementType = 'span'>(
    {
      as,
      children,
      font = 'regular',
      size = '4',
      color = 'blue',
      ...other
    }: TextProps<C>,
    ref?: PolymorphicRef<C>,
  ) => {
    const classes = `${color} ${font} ${size}`
    const Component = as || 'span'

    return (
      <Component {...other} className={classes} ref={ref}>
        {children}
      </Component>
    )
  },
)
```

So this works in that everything within the component code is strongly typed. But the type of `Text` itself is `any` 😭. So after trying and trying and trying, we gave in and explicitly defined the type for `Text` (now including a ref) using a [type annotation](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-annotations-on-variables).

```typescript {1-3,5}
type TextComponent = <C extends React.ElementType = 'span'>(
  props: TextProps<C>,
) => React.ReactElement | null

export const Text: TextComponent = React.forwardRef(
  <C extends React.ElementType = 'span'>(
    {
      as,
      children,
      font = 'regular',
      size = '4',
      color = 'blue',
      ...other
    }: TextProps<C>,
    ref?: PolymorphicRef<C>,
  ) => {
    const classes = `${color} ${font} ${size}`
    const Component = as || 'span'

    return (
      <Component {...other} className={classes} ref={ref}>
        {children}
      </Component>
    )
  },
)
```

`TextComponent` (naming is hard lol) is a function that takes in `TextProps` and returns JSX. In other words, it's a component. This _almost_ gets us there, except now `Text`, from a type perspective, doesn't support a `ref` prop even though from a code perspective it does. 🤦🏾‍♂️ **So the final step was to update `TextProps` to now support the `PolymorphicRef`.**

```typescript {1-4,13}
export type PolymorphicComponentPropsWithRef<
  C extends React.ElementType,
  Props = {}
> = PolymorphicComponentProps<C, Props> & { ref?: PolymorphicRef<C> }

interface Props {
  children: React.ReactNode
  color?: 'red' | 'green' | 'blue'
  font?: 'thin' | 'regular' | 'heavy'
  size?: '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10'
}

type TextProps<C extends React.ElementType> = PolymorphicComponentPropsWithRef<
  C,
  Props
>

type TextComponent = <C extends React.ElementType = 'span'>(
  props: TextProps<C>,
) => React.ReactElement | null
```

This introduces a new helper type called `PolymorphicComponentPropsWithRef` which adds the `PolymorphicRef` to the `Props` so that we can create `TextProps`. We could've made the base `PolymorphicComponentProps` support refs by default (see the `PropsOf` helper). But we were incrementally supporting refs in components, so we needed the separation.

So altogether the new `Text` component with all its reusable helper types looks like (new code highlighted):

```typescript {46-60,71,76-78,80,90,96}
import React from 'react'

// Source: https://github.com/emotion-js/emotion/blob/master/packages/styled-base/types/helper.d.ts
// A more precise version of just React.ComponentPropsWithoutRef on its own
export type PropsOf<
  C extends keyof JSX.IntrinsicElements | React.JSXElementConstructor<any>
> = JSX.LibraryManagedAttributes<C, React.ComponentPropsWithoutRef<C>>

type AsProp<C extends React.ElementType> = {
  /**
   * An override of the default HTML tag.
   * Can also be another React component.
   */
  as?: C
}

/**
 * Allows for extending a set of props (`ExtendedProps`) by an overriding set of props
 * (`OverrideProps`), ensuring that any duplicates are overridden by the overriding
 * set of props.
 */
export type ExtendableProps<
  ExtendedProps = {},
  OverrideProps = {}
> = OverrideProps & Omit<ExtendedProps, keyof OverrideProps>

/**
 * Allows for inheriting the props from the specified element type so that
 * props like children, className & style work, as well as element-specific
 * attributes like aria roles. The component (`C`) must be passed in.
 */
export type InheritableElementProps<
  C extends React.ElementType,
  Props = {}
> = ExtendableProps<PropsOf<C>, Props>

/**
 * A more sophisticated version of `InheritableElementProps` where
 * the passed in `as` prop will determine which props can be included
 */
export type PolymorphicComponentProps<
  C extends React.ElementType,
  Props = {}
> = InheritableElementProps<C, Props & AsProp<C>>

/**
 * Utility type to extract the `ref` prop from a polymorphic component
 */
export type PolymorphicRef<
  C extends React.ElementType
> = React.ComponentPropsWithRef<C>['ref']

/**
 * A wrapper of `PolymorphicComponentProps` that also includes the `ref`
 * prop for the polymorphic component
 */
export type PolymorphicComponentPropsWithRef<
  C extends React.ElementType,
  Props = {}
> = PolymorphicComponentProps<C, Props> & { ref?: PolymorphicRef<C> }

// 👇🏾👇🏾 sample usage in `Text` component 👇🏾👇🏾

interface Props {
  children: React.ReactNode
  color?: Color
  font?: 'thin' | 'regular' | 'heavy'
  size?: '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10'
}

type TextProps<C extends React.ElementType> = PolymorphicComponentPropsWithRef<
  C,
  Props
>

type TextComponent = <C extends React.ElementType = 'span'>(
  props: TextProps<C>,
) => React.ReactElement | null

export const Text: TextComponent = React.forwardRef(
  <C extends React.ElementType = 'span'>(
    {
      as,
      children,
      font = 'regular',
      size = '4',
      color = 'blue',
      ...other
    }: TextProps<C>,
    ref?: PolymorphicRef<C>,
  ) => {
    const classes = `${color} ${font} ${size}`
    const Component = as || 'span'

    return (
      <Component {...other} className={classes} ref={ref}>
        {children}
      </Component>
    )
  },
)
```

Now when we render a `<Text>` component, if the `as` prop is `"label"`, not only does `<Text>` support the `ref` prop, but its type has to be `HTMLLabelElement` (or the generic `HTMLElement`). Type checking will fail when passing other types. 🎉

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/forwarding-refs-polymorphic-react-component-typescript</link>
            <guid isPermaLink="false">forwarding-refs-polymorphic-react-component-typescript</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[refs]]></category>
            <category><![CDATA[polymorphic]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 15 Aug 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Initializing the Firebase Admin Node SDK with env vars]]></title>
            <description><![CDATA[
The [Firebase Admin Node SDK](https://firebase.google.com/docs/admin/setup) is intended to run in a privileged environment. In my ([Next.js](https://nextjs.org/) React) web apps deployed on [Vercel](https://vercel.com/), I use the Admin SDK for scripts that import/export data as well as REST APIs that make read/write Firebase calls to accomplish a task.

In order to initialize the Admin SDK, we first need to generate a private key file from our [Google service account](https://console.firebase.google.com/u/0/project/_/settings/serviceaccounts/adminsdk). We'll get a JSON file containing the private key. It'll look something like this (redacted for obvious reasons):

```json {5}
{
  "type": "service_account",
  "project_id": "[PROJECT_ID]",
  "private_key_id": "xxxx",
  "private_key": "]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/initializing-firebase-admin-node-sdk-env-vars</link>
            <guid isPermaLink="false">initializing-firebase-admin-node-sdk-env-vars</guid>
            <category><![CDATA[divops]]></category>
            <category><![CDATA[firebase]]></category>
            <category><![CDATA[sdk]]></category>
            <category><![CDATA[node]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 08 Aug 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[The non-destructive JavaScript array methods]]></title>
            <description><![CDATA[
In my previous post, we took a deep dive into the [`.reduce()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) method on the JavaScript Array API. This time I want to zoom out and take a look at all of the JavaScript array methods. Well, not all. I only want to focus on those methods that are non-destructive; those methods that don't change the array, but return something new.

With React as well as some state management solutions, [immutability](https://css-tricks.com/understanding-immutability-in-javascript/) is key. So mutating arrays, for instance, is a no-no. So now I've just gotten used to avoiding those methods that mutate the array when possible.

So let's take a look at the methods on the JavaScript Array API that are non-destructive. Hopefully, we can learn something new!

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/non-destructive-javascript-array-methods</link>
            <guid isPermaLink="false">non-destructive-javascript-array-methods</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[arrays]]></category>
            <category><![CDATA[map]]></category>
            <category><![CDATA[filter]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 25 Jul 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Learn the Array reduce method by re-implementing lodash functions]]></title>
            <description><![CDATA[
The built-in [JavaScript `Array` object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) has lots of helpful methods that allow us to manipulate arrays. I use [`.map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) and [`.filter()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) all the time when I'm transforming data. Arguably the most powerful, yet also least understood method is [`.reduce()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce). It allows us to basically transform an array into nearly anything else: another array, an object, a boolean, a number, etc.

So let's learn how `.reduce()` works by re-implementing [`lodash`](https://lodash.com/) functions.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/learn-array-reduce-method-reimplementing-lodash-functions</link>
            <guid isPermaLink="false">learn-array-reduce-method-reimplementing-lodash-functions</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[arrays]]></category>
            <category><![CDATA[reduce]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 18 Jul 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Exploring the JavaScript Promise API methods]]></title>
            <description><![CDATA[
[ECMAScript 2021](https://ui.dev/es2021/) introduced a new static method to the `Promise` object called [`Promise.any`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/any). In total there are now 6 static methods on the `Promise` object:

- [`Promise.all`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all)
- [`Promise.allSettled`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled)
- [`Promise.any`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/any)
- [`Promise.race`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race)
- [`Promise.resolve`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve)
- [`Promise.reject`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject)

We use promises everywhere in JavaScript code for handling asynchronous code. But when would we use one method over another? Well let's walk through use cases for each to find out!

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/exploring-javascript-promise-api-methods</link>
            <guid isPermaLink="false">exploring-javascript-promise-api-methods</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[promise]]></category>
            <category><![CDATA[async]]></category>
            <category><![CDATA[await]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 11 Jul 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Tools to catch accessibility errors in JavaScript applications]]></title>
            <description><![CDATA[
I've learned a lot about accessibility these last 2 years working at Stitch Fix. I don't know if it's because I've been working on our design system where I've had to make accessible components. Or if it's simply that the industry has raised its collective awareness of the needs for developing accessibility features.

**While accessibility features are an absolute necessity for some to use our sites, many of them are also beneficial to everyone.** High color contrast is important for the visually impaired, but also comes in handy when a "well-sighted" person is on their phone in the sunlight. Having proper keyboard interactions is critical for those who cannot use a mouse, but are also useful for keyboard power users.

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Good <a href="https://twitter.com/hashtag/a11y?src=hash&amp;ref_src=twsrc%5Etfw">#a11y</a> features are beneficial for lots of people. <a href="https://t.co/2RMnTzseey">pic.twitter.com/2RMnTzseey</a></p>&mdash; Chris Heilmann (@codepo8) <a href="https://twitter.com/codepo8/status/1409559894265565188?ref_src=twsrc%5Etfw">June 28, 2021</a></blockquote>

[React](https://reactjs.org/) has gotten a bad rep about creating unaccessible apps. I've even seen people ask if React itself is unaccessible. I can't be 100% certain, but I don't think unaccessible apps are not unique to React. It just happens to be the most popular web development library right now. **I think apps built with all of the JavaScript frameworks have accessibility problem.** They make it so much easier to build interactivity. But unless we know the rules, we can just as easily build that interactivity in an unaccessible manner.

Instead, we should be creating accessible UIs making the full use of the semantic HTML elements and CSS. Anything clickable should be a `<button>` element and anything that navigates should be an `<a>` element. A UI that lets the user pick one or more options should be radio or checkbox `<input>` elements. It takes a bit more CSS to override the default behavior of these tags and style them the way we want, but **then we don't have to worry about recreating all the behavior the browser does for them**. And when we need to build UIs that native HTML cannot handle, we can always lean on [ARIA](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA) to help the browser understand what's going on.

But this post isn't about how to write accessible web apps. Instead it's about how we can validate, using automated tooling, whether or not our app is accessible. There are five tools that I want to discuss that can help us catch accessibility issues in web apps at several different stages of development/test/deployment. **My personal experience is with React applications, of course, but most of the tools we'll look at are framework-agnostic.**

Let's jump right in!

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/tools-catch-accessibility-errors-javascript-applications</link>
            <guid isPermaLink="false">tools-catch-accessibility-errors-javascript-applications</guid>
            <category><![CDATA[accessibility]]></category>
            <category><![CDATA[a11y]]></category>
            <category><![CDATA[testing]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[vue]]></category>
            <category><![CDATA[angular]]></category>
            <category><![CDATA[svelte]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Mon, 05 Jul 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Catch warnings in Jest tests]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/catch-warnings-jest-tests</link>
            <guid isPermaLink="false">catch-warnings-jest-tests</guid>
            <category><![CDATA[divops]]></category>
            <category><![CDATA[jest]]></category>
            <category><![CDATA[testing]]></category>
            <category><![CDATA[warnings]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 27 Jun 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Creating a React controlled components pattern custom Hook]]></title>
            <description><![CDATA[
Two weeks ago I wrote about [picking the right React component pattern](/blog/picking-right-react-component-pattern/) for shared components that we build. One of the patterns I discussed was the controlled components pattern that makes our custom component act much like [controlled HTML form elements](https://fb.me/react-controlled-components).

I showed this snippet of code for a `Pagination` component that either wants to be an uncontrolled or controlled component depending on what props the parent passes.

```js {8-9,11-26}
import { useState } from 'react'

const Pagination = ({
  // `initialPage` is when it's uncontrolled
  initialPage = 1,

  // `page` & `onPageChange` are when it's controlled by parent
  page: controlledPage,
  onPageChange,
}) => {
  const isControlled = controlledPage !== undefined
  const [pageState, setPage] = useState(initialPage)

  // when `page` prop is specified, the component is controlled by parent
  // otherwise it's uncontrolled so use internal `pageState`
  const page = isControlled ? controlledPage : pageState

  const setNewPage = (nextPage) => {
    // only set internal state if `Pagination` is uncontrolled
    if (!isControlled) {
      setPage(nextPage)
    }

    // call `onPageChange` if it exists using optional chaining
    onPageChange?.(nextPage)
  }

  return (
    <div>
      {page > 1 && (
        <Button
          size="small"
          variant="secondary"
          onClick={() => setNewPage(page - 1)}
        >
          Previous
        </Button>
      )}
      <span>Current page: {page}</span>
      <Button
        size="small"
        variant="secondary"
        onClick={() => setNewPage(page + 1)}
      >
        Next
      </Button>
    </div>
  )
}
```

The `Pagination` component now maintains the internal state when it is uncontrolled, but doesn't use it when it is controlled (i.e. the `page` prop is specified). **But the code to support the controlled components pattern muddies up the `Pagination`.** This is a perfect time to extract the logic into a [custom Hook](https://reactjs.org/docs/hooks-custom.html) to not only clean up the `Pagination` component, but also reuse the logic elsewhere.

I stumbled across a `useControlled` custom Hook while code spelunking in the [`material-ui` codebase](https://github.com/mui-org/material-ui). Here is an adaptation of the implementation:

```js
// hooks.js

import { useState, useEffect, useRef, useCallback } from 'react'

const useControlled = ({ controlledValue, initialValue, name }) => {
  const isControlled = controlledValue !== undefined
  const { current: origIsControlled } = useRef(isControlled)
  const [internalValue, setInternalValue] = useState(initialValue)
  const { current: origInitialValue } = useRef(initialValue)
  const value = origIsControlled ? controlledValue : internalValue

  useEffect(() => {
    if (process.env.NODE_ENV !== 'production') {
      if (origIsControlled !== isControlled) {
        console.warn(
          `"${name}" is changed from ${
            origIsControlled
              ? 'uncontrolled to controlled'
              : 'controlled to uncontrolled'
          }.`,
        )
      }
    }
  }, [origIsControlled, isControlled, name])

  useEffect(() => {
    if (process.env.NODE_ENV !== 'production') {
      if (!origIsControlled && origInitialValue !== initialValue) {
        console.warn(
          `"${name}" is changing its defaultValue after being initialized. Make "${name}" a controlled component instead.`,
        )
      }
    }
  }, [origInitialValue, initialValue, name, origIsControlled])

  const setValueIfUncontrolled = useCallback(
    (newValue) => {
      if (!origIsControlled) {
        setInternalValue(newValue)
      }
    },
    [origIsControlled],
  )

  return [value, setValueIfUncontrolled]
}
```

Don't worry too much about the length of the code. Over half of it is helpful warning messages. So what I want to do is break down this custom Hook to explain how it composes 6 built-in Hooks to provide the controlled component pattern.

Before we begin the walk-through, this is how we'd use the `useControlled` custom Hook in our `Pagination` component:

```js {8-12,15}
import { useControlled } from './hooks'

const Pagination = ({
  initialPage = 1,
  page: controlledPage,
  onPageChange,
}) => {
  const [page, setPage] = useControlled({
    controlledValue: controlledPage,
    initialValue: initialPage,
    name: 'Pagination.page',
  })

  const setNewPage = (nextPage) => {
    setPage(nextPage)
    onPageChange?.(nextPage)
  }

  return (
    <div>
      {page > 1 && (
        <Button
          size="small"
          variant="secondary"
          onClick={() => setNewPage(page - 1)}
        >
          Previous
        </Button>
      )}
      <span>Current page: {page}</span>
      <Button
        size="small"
        variant="secondary"
        onClick={() => setNewPage(page + 1)}
      >
        Next
      </Button>
    </div>
  )
}
```

It's a lot simpler, right? `Pagination` can return to focusing on the UX, not all of the state management. The `useControlled` Hook now handles all of that. `Pagination` receives the `page` state and update function (`setPage`) much like what we would get from [`useState`](https://reactjs.org/docs/hooks-reference.html#usestate).

Let's dive in.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/create-react-controlled-components-pattern-custom-hook</link>
            <guid isPermaLink="false">create-react-controlled-components-pattern-custom-hook</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[hooks]]></category>
            <category><![CDATA[controlled]]></category>
            <category><![CDATA[components]]></category>
            <category><![CDATA[pattern]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 13 Jun 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Extracting TypeScript types from functions, objects & arrays]]></title>
            <description><![CDATA[
A 3rd-party library written in TypeScript likely makes use of lots of internal types to support its API. Libraries typically export additional helper types that we may need in order to use the API. But sometimes the library forgets types or there are types that they did not expect we would need. So I want to share some TypeScript tips for extracting types trapped in functions, objects, and arrays.

Let's say that we're using the following function from a library:

```typescript {28-30}
// index.ts (in @third-party-lib/api)

interface Player {
  name: string
  dob: Date
  number: number
  position: string
  height: number
  weight: number
}

interface Location {
  city: string
  state: string
}

interface TeamInfo {
  name: string
  location: Location
  players: Player[]
}

interface Team extends TeamInfo {
  id: string
  dateCreated: Date
}

export const createTeam = (info: TeamInfo): Promise<Team> => {
  // do stuff asynchronously...
}
```

The `createTeam` function takes a single parameter that's an object with three properties: `name`, `location`, and `players`. It returns a `Team` object wrapped in a `Promise` because the function is async.

Let's say the common use case for calling `createTeam()` is to pass a big object literal:

```typescript
import { createTeam } from '@third-party-lib/api'

const run = async () => {
  const team = await createTeam({
    name: 'Houston Rockets',
    location: { city: 'Houston', state: 'TX' },
    players: [
      {
        name: 'Christian Wood',
        dob: new Date('9/27/1995'),
        number: 35,
        position: 'C',
        height: 82,
        weight: 214,
      },
      {
        name: 'Kevin Porter Jr.',
        dob: new Date('5/4/2000'),
        number: 3,
        position: 'SG',
        height: 76,
        weight: 203,
      },
      // ...
    ],
  })
}

run()
```

Even though we never declared the `Player` or `Location` types directly, TypeScript is able to associate them with the object literals. This is because the types of the properties of the object literals match the properties defined in the TypeScript interfaces.

But what if we need to use the `Player` or `Location` type in our application outside of calling `createTeam`?

```typescript {1}
const validatePlayer = (player: Player): boolean => {
  // code that validates a `Player` object
}
```

**And what if this library failed to export the `Player`, `Location`, and other types?** How would we go about getting them? Well, we _could_ create our own mirror types from inspecting the [declaration files](https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html). But then they could get out of sync. Instead, let's extract the types directly from the `createTeam()` function.

Let's first start with extracting the parameters of `createTeam()` using the [`Parameters<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#parameterstype) generic utility type.

```typescript
type CreateTeamParams = Parameters<typeof createTeam>
// CreateTeamParams = [info: TeamInfo]
```

The `CreateTeamParams` is an array type of a single element, the `TeamInfo` type. Again, `TeamInfo` wasn't exported, so we need a way to get the TypeScript type out of the array type. We can use [indexed access types](https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html) to extract the `TeamInfo` type.

```typescript
type ExtractedTeamInfo = CreateTeamParams[0]
// ExtractedTeamInfo = TeamInfo
```

Nice! **We can index into the array type much like we can index into a normal JavaScript array object.** So we now have `TeamInfo` which we've named `ExtractedTeamInfo`. I would normally just name it `TeamInfo`, but to be clear that it's a type alias of the actual `TeamInfo` interface, I've named it `ExtractedTeamInfo`.

So now that we have `ExtractedTeamInfo` we need to get both the `Player` and `Location` types. Let's try getting `Location` first.

```typescript
type ExtractedLocation = ExtractedTeamInfo['location']
// ExtractedLocation = Location
```

Simple enough right? Just like we can index into an array type, **we can also get the types of properties of interfaces / object types using indexed access types**. We combine both types of indexed access types to retrieve `Player`.

```typescript
type ExtractedPlayers = ExtractedTeamInfo['players']
// ExtractedPlayers = Player[]
type ExtractedPlayer = ExtractedPlayers[number]
// ExtractedPlayer = Player
```

Noticed that we used `[number]` to get the `ExtractedPlayer`. `ExtractedPlayers` is an array of `Player` types, so we're not looking for one at a specific index. Using `[number]` gets us the type of the array's elements, i.e. `Player`.

Now we have `ExtractedLocation` & `ExtractedPlayer` as types to use as we need.

```typescript {1}
const validatePlayer = (player: ExtractedPlayer): boolean => {
  // code that validates a `Player` object
}
```

Oh, but what about `Team`? It's wrapped up in the `Promise` _returned_ by `createTeam()`. So first let's get that return type of `createTeam()`.

```typescript
type CreateTeamPromise = ReturnType<typeof createTeam>
// CreateTeamPromise = Promise<Team>
```

We use the [`ReturnType<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#returntypetype) generic utility type to get the type `Promise<Team>`.

And finally we need to unwrap the promise type so we can get just `Team`. Unfortunately, there's no simple index type that we can use to remove the `Promise<T>`. But we can create our own [conditional type](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#conditional-type-constraints) to do the unwrapping.

```typescript {3-5}
// checks to see if the `Type` is a promise wrapping an underlying type.
// if so it returns the underlying type. if not, it returns back the type.
type Unwrapped<Type> = Type extends Promise<infer WrappedType>
  ? WrappedType
  : Type

type ExtractedTeam = Unwrapped<CreateTeamPromise>
// ExtractedTeam = Team
```

So this is definitely some advanced TypeScripting going on here. Let me try to break it down. Not only is `Unwrapped<Type>` a generic conditional type, but it's using [type inference](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#inferring-within-conditional-types) within a generic conditional type. **The `infer` keyword allows us to "peek into" the generic type to see what it might be.** If it matches `Promise<WrappedType>` then the conditional returns `WrappedType` (the type the promise was wrapping). Otherwise, it'll just return the entire type. This "unwrapping" pattern can be used for any custom generic types you define as well. Just replace `Promise` with your type.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/extracting-typescript-types-functions-objects-arrays</link>
            <guid isPermaLink="false">extracting-typescript-types-functions-objects-arrays</guid>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[tips]]></category>
            <category><![CDATA[types]]></category>
            <category><![CDATA[hacks]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 06 Jun 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Picking the right React component pattern]]></title>
            <description><![CDATA[
A few months ago I wrote about [React custom Hooks vs. Mixins](/blog/react-custom-hooks-mixins/) discussing how they were surprisingly similar patterns for sharing stateful, non-visual logic. It got me thinking about the other React component patterns. These patterns exist to create reusable and extendable components so that we don't have to rewrite **display/layout, visual look-and-feel, and/or UI logic**.

But before we look at these patterns, let's quickly review the standard React component with normal props. It's the easiest to develop and also the easiest to use.

```js
import classNames from 'classnames'

const Button = ({ children, onClick, size = 'large', variant = 'primary' }) => {
  return (
    <button onClick={onClick} className={classNames(variant, size)}>
      {children}
    </button>
  )
}
```

The `Button` component has 5 props that allow its parent component to configure it. The `children` prop configures the display, the `size` and `variant` props configure the visual look-and-feel, and the `onClick` prop configures the UI logic.

The combination of just those 4 props allow for various different button user experiences.

```js
import { useState } from 'react'

const Pagination = ({ initialPage = 1 }) => {
  const [page, setPage] = useState(initialPage)

  return (
    <div>
      {page > 1 && (
        <Button
          size="small"
          variant="secondary"
          onClick={() => setPage((curPage) => curPage - 1)}
        >
          Previous
        </Button>
      )}
      <span>Current page: {page}</span>
      <Button
        size="small"
        variant="secondary"
        onClick={() => setPage((curPage) => curPage + 1)}
      >
        Next
      </Button>
    </div>
  )
}
```

Normal props are great because it gives the shared component total control. The only way to change the component is through those exposed props. However, when we need a shared component to be flexible (either in its UI logic, visual look-and-feel, or display/layout) normal props begin to break down. We start having to expose more and more props to allow parent components the flexibility in customization that they desire.

So there are other React component patterns to offload responsibility to the parent component of a shared component in order to make it more flexible. **This process is typically called inversion of control.** I want to break down the most popular React patterns, describing their primary use case(s).

Let's jump right in!

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/picking-right-react-component-pattern</link>
            <guid isPermaLink="false">picking-right-react-component-pattern</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[placeholder]]></category>
            <category><![CDATA[props]]></category>
            <category><![CDATA[polymorphic]]></category>
            <category><![CDATA[components]]></category>
            <category><![CDATA[controlled]]></category>
            <category><![CDATA[uncontrolled]]></category>
            <category><![CDATA[render]]></category>
            <category><![CDATA[compound]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Mon, 31 May 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Create a dynamic sitemap with a Next.js API route]]></title>
            <description><![CDATA[
Sitemaps for our apps, blogs or other sites are important because it allows search engines like Google to more intelligently crawl the site. Typically a search engine can discover the majority of a site if the pages are properly linked. But a sitemap is especially helpful if the site has pages that aren't well linked, is really large, or is pretty new (with few sites linking to it).

Google has a [guide for building a sitemap](https://developers.google.com/search/docs/advanced/sitemaps/build-sitemap) that you can use to manually build your own for your [Next.js](https://nextjs.org/) app. This can work well if the pages in your site are constant or you can determine them at build time. But if you have user-generated content, you likely have [dynamic routes](https://nextjs.org/docs/routing/dynamic-routes). And as a result, there will likely be new pages added in between builds. **So let's see how we can use a Next [API route](https://nextjs.org/docs/api-routes/introduction) to build a constantly updating sitemap.**

Here's the full code for the API route:

```js
// /src/pages/api/sitemap.js

import { createGzip } from 'zlib'
import { SitemapStream } from 'sitemap'

const STATIC_URLS = [
  // all the non-dynamic URLs
]

const sitemapApi = async (req, res) => {
  // ensure response is XML & gzip encoded
  res.setHeader('Content-Type', 'application/xml')
  res.setHeader('Content-Encoding', 'gzip')

  // makes necessary API calls to get all the dynamic
  // urls from user-gen content
  const userGenPageUrls = await getUserGeneratedPages()

  const sitemapStream = new SitemapStream()
  const pipeline = sitemapStream.pipe(createGzip())

  // write static pages to sitemap
  STATIC_URLS.forEach((url) => {
    sitemapStream.write({ url })
  })

  // write user-generated pages to sitemap
  userGenPageUrls.forEach((url) => {
    sitemapStream.write({ url })
  })

  sitemapStream.end()

  // stream write the response
  pipeline.pipe(res).on('error', (err) => {
    throw err
  })
}

export default sitemapApi
```

That gives the sitemap a URL route of `/api/sitemap`. Typically sitemaps live at the root at `/sitemap.xml`. We can use [Next rewrites](https://nextjs.org/docs/api-reference/next.config.js/rewrites) in the `next.config.js`, however, to rewrite `/sitemap.xml` to the real `/api/sitemap` route.

```js
// next.config.js

module.exports = {
  rewrites: async () => [
    {
      source: '/sitemap.xml',
      destination: '/api/sitemap',
    },
  ],
}
```

And that's it! 🎉 Feel free to copy and paste and be on your merry way. But if you'd like a breakdown of how it all works, I've got your covered. 😉

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/create-dynamic-sitemap-nextjs-api-route</link>
            <guid isPermaLink="false">create-dynamic-sitemap-nextjs-api-route</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[next]]></category>
            <category><![CDATA[sitemap]]></category>
            <category><![CDATA[api]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 23 May 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Looping in React]]></title>
            <description><![CDATA[
Last week I talked about 6 different ways to [conditional render JSX markup within a React component](/blog/conditional-rendering-react/). Looping in JSX within a React component is another aspect that trips up newcomers to React. Based on other templating languages, we might expect to be able to loop in JSX like so:

```js
// THIS DOESN'T WORK!!! 👎🏾👎🏾👎🏾
const Teams = ({ teams }) => {
  return (
    <ul>
      <% for (const team of teams) { %>
        <li>{team.name} ({team.abbreviation})</li>
      <% } >
    </ul>
  )
}
```

All we want to do is render out an `<li>` for every `team` in the `teams` prop. But JSX doesn't provide it's own loop construct. It offloads looping to JavaScript. This feels totally unexpected at first, but once we get used to it actually opens up way more possibilities.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/looping-in-react</link>
            <guid isPermaLink="false">looping-in-react</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[loop]]></category>
            <category><![CDATA[logic]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 16 May 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Conditional rendering in React]]></title>
            <description><![CDATA[
Because React uses [JSX](https://reactjs.org/docs/introducing-jsx.html) for rendering component UI, and JSX is ["Just JavaScript"™](https://reactjs.org/docs/introducing-jsx.html#jsx-represents-objects) under the hood, there is no special template syntax for conditionals like we find in other JavaScript frameworks. While this may seem like a drawback (especially to newcomers), it allows us to use the full power of JavaScript to conditionally render UI within a React component.

If you're coming from an HTML templating language like [Handlebars](https://handlebarsjs.com/), [EJS](https://ejs.co/), or others, you may think you could conditionally render content within a React component like so:

```js
// THIS DOESN'T WORK!!! 👎🏾👎🏾👎🏾
const Page = ({ results }) => {
  return (
    <main>
      <h1>Your results</h1>

      <p>View your results below</p>

      <% if (results.length) { %>
        <Items items={results} />
      <% } %>
    </main>
  )
}
```

We're _trying_ to conditionally render the `<Items />` component if the `results` array has items in it. But JSX doesn't work this way. Conditionally rendering content in a component is a fundamental React skill. It comes up all the time. As such, it's included in my [Zero to React with Hooks Minishop](/minishops/zero-to-react-with-hooks/).

So let's look at all the various ways we can accomplish conditional Rendering in React.

## 1. Element variables

We can store JSX in variables. When we want to conditionally render some content, we can conditionally assign values to variables and then render them.

```js {2-6,12}
const Page = ({ results }) => {
  let resultsUi

  if (results.length) {
    resultsUi = <Items items={results} />
  }

  return (
    <main>
      <h1>Your results</h1>
      <p>View your results below</p>
      {resultsUi}
    </main>
  )
}
```

We initialize `resultsUi` to `undefined`. If there are no items in `results`, then we'll render `undefined` in the UI, and React will render nothing. However, if there are items in `results`, we assign `<Items />` to `resultsUi` and that's what we'll render instead. It's kinda mind boggling that we can assign "markup" to a variable. But because JSX under the hood is a call to [`React.createElement()`](https://reactjs.org/docs/react-without-jsx.html), it totally works.

And what if we also want to render some UI when there are no results?

```js {2-6,12}
const Page = ({ results }) => {
  let resultsUi = <p>There are no results to view.</p>

  if (results.length) {
    resultsUi = <Items items={results} />
  }

  return (
    <main>
      <h1>Your results</h1>
      <p>View your results below</p>
      {resultsUi}
    </main>
  )
}
```

When we need to render something for both the `false` and the `true` case, we can initialize `resultsUi` to the `false` condition and then reassign on the `true`.

We can apply the same approach even if there are multiple conditions. We can use `if`, one or more `if else` statements, and an `else` statement. Or we can use a `switch` instead.

**This used to be my preferred method of conditional rendering earlier on because I liked how it kept the JSX "clean."** There was no logic in the JSX; just rendering. But it can be verbose, especially for something as simple as this example. The rendering logic and the rendering itself are separated. And if there are multiple conditionally rendered pieces of UI, we have to define multiple of these variables up top.

## 2. Inline logical `&&`

It's more common, however, to do the conditional rendering within the context of the JSX. And probably the most common inline approach is using the logical `&&`.

```js {6}
const Page = ({ results }) => {
  return (
    <main>
      <h1>Your results</h1>
      <p>View your results below</p>
      {results.length > 0 && <Items items={results} />}
    </main>
  )
}
```

The curly braces (`{}`) in JSX take any JavaScript expression. Typically we'll only put a variable like we did with the `{resultsUi}` element variable. But we can have any expression that results in valid JSX content.

So here if there are no items in `results`, then the expression returns `false`. React renders nothing for `false`. However, if there are items in `results` (`results.length > 0` is `true`), then it'll render the `<Items />` component.

I held out for several years using this approach for a couple of reasons. First, there's a subtle gotcha. If we wrote the expression excluding the `> 0`:

```js {6}
const Page = ({ results }) => {
  return (
    <main>
      <h1>Your results</h1>
      <p>View your results below</p>
      {results.length && <Items items={results} />}
    </main>
  )
}
```

Our UI would render a `0` when there are no items in `results`. **React doesn't render `false` but it will render `0`.** So while `0` is a [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) value just like `false`, the end result is quite different. I've definitely made this mistake a number of times.

The other reason is because ouf formatting. In this example, the conditional is a one-liner, so it's easy. But if the conditional markup we want to render has multiple elements and components with multiple props, the formatting gets messier. And developers would format it in ways that made it hard for me to understand where the conditional started and ended.

[Prettier](https://prettier.io/) got rid of this problem completely because it provides consistent formatting as well as visually "correct" formatting.

## 3. Inline ternary

The logical `&&` approach works when we only need to render something when the inline conditional is `true`. We can use a [ternary operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) when we want to use inline conditional rendering to render something for both the `false` and `true` conditions.

```js {6-10}
const Page = ({ results }) => {
  return (
    <main>
      <h1>Your results</h1>
      <p>View your results below</p>
      {results.length ? (
        <Items items={results} />
      ) : (
        <p>There are no results to view.</p>
      )}
    </main>
  )
}
```

It's like using the `if`-`else` example above with the element variable except it's inline as a single expression. This is the common way developers write conditional rendering when they have to render something for both cases.

I used to avoid this approach as well for many of the same reasons as the logical `&&`. Many times the condition itself will be a compound condition (with have a logical `&&` or logical `||`) so it felt like a lot of logic going on within the JSX. And the formatting here would be even worse. But, again, Prettier makes that a non-issue. And folks over time have gotten use to using ternary expressions in general.

## 4. Component early return

Let's go back to the logical `&&` solution where we only needed to render for the `true` case:

```js
const Page = ({ results }) => {
  return (
    <main>
      <h1>Your results</h1>
      <p>View your results below</p>
      {results.length > 0 && <Items items={results} />}
    </main>
  )
}
```

Another alternative is to push the conditional down into the rendered component.

```js {4-6,16}
const Items = ({ items }) => {
  // if there are no items, prevent itself from rendering
  // by returning `null` early
  if (!items.length) {
    return null
  }

  // render out the items
}

const Page = ({ results }) => {
  return (
    <main>
      <h1>Your results</h1>
      <p>View your results below</p>
      <Items items={results} />
    </main>
  )
}
```

So now, we always render the `<Items />` component. It becomes responsible for not rendering itself when there are no items. **It accomplishes this by return `null` early instead of returning normal JSX.** This approach comes in handy if many components render `<Items />` components. Instead of having all of those components conditionally render `<Items />` based on the data they pass to it, they can all render it normally and `Items` will prevent itself from rendering.

## 5. Helper function

If there are a lot of calculations needed to construct a condition, it would be nice to have them grouped together as well as located close to the render. I've used helper functions for this.

```js {2-8,14}
const Page = ({ results }) => {
  const renderResults = () => {
    if (!results.length) {
      return <p>There are no results to view.</p>
    }

    return <Items items={results} />
  }

  return (
    <main>
      <h1>Your results</h1>
      <p>View your results below</p>
      {renderResults()}
    </main>
  )
}
```

So we were able to write this condition using a ternary, so of course there is really no advantage in wrapping _this_ code in a function. But this simple example explains the code structure.

**In my opinion, a helper function can be better than having multiple variables to calculate a condition at the top of the component.** This is especially when there are multiple calculations needed for multiple conditionally rendered UI.

This approach puts the calculations, condition and UI rendering together. It's kind of a hybrid of the element variables approach because it keeps the JSX "clean" yet still allows the UI and conditions to be collocated.

However, it does separate the final component rendering. There is an inline option for using helper functions.

```js {6-12}
const Page = ({ results }) => {
  return (
    <main>
      <h1>Your results</h1>
      <p>View your results below</p>
      {(() => {
        if (!results.length) {
          return <p>There are no results to view.</p>
        }

        return <Items items={results} />
      })()}
    </main>
  )
}
```

The inline helper function is an [Immediately-Invoked Function Expression (IIFE)](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) for rendering JSX. I've never in my 6+ years of writing React code ever done this. Or even thought to do it really. But I recently saw it and had to include it just for funsies. 😂

## 6. JSX control statements

Honestly, one of the 5 options above should suffice. But I did want to share an option that used to be more popular in the beginning when JSX was still new and folks hadn't quite gotten the hang of just using JavaScript.

The [`jsx-control-statements`](https://github.com/AlexGilleran/jsx-control-statements) Babel plugin allows us to use component syntax to write conditions.

```js {6-8}
const Page = ({ results }) => {
  return (
    <main>
      <h1>Your results</h1>
      <p>View your results below</p>
      <If condition={results.length}>
        <Items items={results} />
      </If>
    </main>
  )
}
```

It's a [Babel plugin](https://babeljs.io/docs/en/plugins/) so it transforms our code. It doesn't execute at runtime. In fact, it transforms our code to a ternary!

```js {6}
const Page = ({ results }) => {
  return (
    <main>
      <h1>Your results</h1>
      <p>View your results below</p>
      {results.length ? <Items items={results} /> : null}
    </main>
  )
}
```

If we have multiple conditions, there are the `<Choose>`, `<When>`, and `<Otherwise>` components.

```js {6-13}
const Page = ({ results }) => {
  return (
    <main>
      <h1>Your results</h1>
      <p>View your results below</p>
      <Choose>
        <When condition={results.length}>
          <Items items={results} />
        </When>
        <Otherwise>
          <p>There are no results to view.</p>
        </Otherwise>
      </Choose>
    </main>
  )
}
```

This code will be transformed into a ternary as well.

```js {6-10}
const Page = ({ results }) => {
  return (
    <main>
      <h1>Your results</h1>
      <p>View your results below</p>
      {results.length ? (
        <Items items={results} />
      ) : (
        <p>There are no results to view.</p>
      )}
    </main>
  )
}
```

If I had known about this plugin 5 years ago, I may have considered using it just because it keeps the render "clean." Even logic is expressed as components! But at this point, we've all got a hang of logic using the logical `&&` and ternaries. Plus I'm not quite sure how nicely this would play with TypeScript, so it would be a non-starter for me!

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/conditional-rendering-react</link>
            <guid isPermaLink="false">conditional-rendering-react</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[jsx]]></category>
            <category><![CDATA[conditional]]></category>
            <category><![CDATA[rendering]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 09 May 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[End-to-end testing with Firebase Emulator and Github Actions]]></title>
            <description><![CDATA[
When running end-to-end (E2E) tests for an application that changes data, we need to have a separate environment in which we can run the tests. This way when the app creates new data or updates existing data, that test data isn't in our production app.

I recently added end-to-end tests to [NBA Player Tiers](https://nbaplayertiers.com) (a [Next.js](https://nextjs.org/) React app) using [Cypress](https://www.cypress.io/), a JavaScript end-to-end testing framework. NBA Player Tiers uses [Cloud Firestore](https://firebase.google.com/docs/firestore) (from [Firebase](https://firebase.google.com/)) as its DB and [Github actions](https://github.com/features/actions) for its continuous integration (CI) environment. The challenge was to get all 4 of these tools to work together in order to **run a production build of my Next.js app against a separate Firestore environment so that I could run the Cypress E2E tests in a Github workflow.** 😅

Let's get our [DivOps](https://www.jonathancreamer.com/announcing-div-ops/) on.

## Next.js

Cypress is web application agnostic. You could use it to test a [Ruby on Rails](https://rubyonrails.org/) web application. But because we write Cypress tests in JavaScript, folks typically use it with JavaScript web applications like React, Vue, etc. NBA Player Tiers is a [Next.js](https://nextjs.org/) React app, so naturally I'm focusing on Next.js in this post.

One of the major features of a Next.js app is that it can pre-render pages using static-site generation when building the app. If you're interested, you can check out the post I wrote on the [various ways Next.js renders](/blog/50-shades-react-rendering-nextjs/). If a page retrieves data during the build step, it's going to retrieve it from the production DB. But for the purposes of E2E testing, we need it to retrieve the data from a test DB we spin up.

**Needing both app building as well as regular app running to work against a test DB is something unique to Next.js and other static-site generators.** We'll see the solution to the problem in the following sections.

## Cloud Firestore

[Firebase](https://firebase.google.com/) provides the production DB via [Cloud Firestore](https://firebase.google.com/docs/firestore) along with [client-side](https://firebase.google.com/docs/web/setup) and [server-side](https://firebase.google.com/docs/admin/setup) JavaScript SDKs. Now there is _a lot_ that goes into setting up Firebase & Cloud Firestore and using them within our app. But that's not the focus of this post. So I'm assuming that you already have that done or will follow the linked docs to do so.

Instead, I want to focus on setting up a testing environment using the [Firebase Local Emulator Suite](https://firebase.google.com/docs/emulator-suite). Actually, the emulator is also a great for local development so that we're not developing new features against the production DB. The Firebase emulator CLI allows for importing data as it starts up. **So the first step is to get an export of the data from the production DB to use both for local development and testing environments.**

Unfortunately, exporting data from Cloud Firestore is anything but straightforward. Instead of having an export button that saves files that the emulator can import, we have to follow a series of convoluted steps to get those files on our machine. The Firebase team is apparently working on providing a streamlined process, but until then we need to follow this guide: [How to import production data from Cloud Firestore to the Local Emulator](https://medium.com/firebase-developers/how-to-import-production-data-from-cloud-firestore-to-the-local-emulator-e82ae1c6ed8).

By default with Next, we have `"dev"` (run a local dev server), `"build"` (build the app for production use), and `"start"` (run a production-like app) scripts in our `package.json`.

```json
{
  "name": "player-tiers",
  "private": true,
  "scripts": {
    "dev": "next dev -p 3020",
    "build": "next build",
    "start": "next start -p 3021"
  }
}
```

> I run the local development environment on port `3020` because the default port is `3000` and lots of other apps like to use `3000` as well. So instead of it sometimes using `3000`, sometimes using `3001` or even `3002`, I just set it to `3020`. I run the production server on port `3021` in case I want to also run the production environment locally on my machine to test in a production-like environment.

But now we want to run these against the Firebase Local Emulator with imported data. First follow the instructions to [install & configure the emulator](https://firebase.google.com/docs/emulator-suite/install_and_configure). Then add additional scripts to run the emulator and import the data before running our scripts.

```json {6,8,10}
{
  "name": "player-tiers",
  "private": true,
  "scripts": {
    "dev": "next dev -p 3020",
    "dev:emulator": "firebase emulators:exec 'npm run dev' --import=scripts/firebase/firestore-export/ --ui",
    "build -p 3021": "next build",
    "build:emulator": "firebase emulators:exec 'npm run build' --import=scripts/firebase/firestore-export/",
    "start": "next start",
    "start:emulator": "firebase emulators:exec 'npm start' --import=scripts/firebase/firestore-export/"
  }
}
```

> Most guides will say to use [`emulators:start`](https://firebase.google.com/docs/functions/local-emulator#run_the_emulator_suite) in a separate tab when running a web server like we do with `"dev"` & `"start"`, but I found it more convenient to tie them together with `emulators:exec`. When I stop the web server I also want the data environment to stop as well. I always run the `"dev:emulator"` script as I develop locally. And we'll see `"build:emulator"` and `"start:emulator"` used in the CI phase.

## Cypress

Now to the end-to-end testing tool, Cypress. [Setting up Cypress](https://docs.cypress.io/guides/getting-started/installing-cypress#npm-install) is fairly straightforward and it has a very friendly developer experience for both writing and running E2E tests. But again, writing the tests is not my focus. There are [many guides](https://docs.cypress.io/guides/getting-started/writing-your-first-test#Add-a-test-file) that explain how to write quality end-to-end Cypress tests. My focus is on configuring Cypress so that it can run properly in the test environment.

One of the Cypress best practices is to [set a global `baseUrl`](https://docs.cypress.io/guides/references/best-practices#Setting-a-global-baseUrl) in the `cypress.json` [configuration file](https://docs.cypress.io/guides/references/configuration). This way commands like `cy.visit()` can omit the base URL and can run against different environments.

```json
{
  "baseUrl": "http://localhost:3020"
}
```

With the `baseUrl` set to `"http://localhost:3020"`, we can run our tests against the dev environment (via "`dev:emulator`"), but not against the production-like environment (`start:emulator`). When running against the production-like environment we'll use for the end-to-end tests, we need the `baseUrl` to be `http://localhost:3021`.

Well it turns out that Cypress also supports the `CYPRESS_BASE_URL` [environment variable](https://docs.cypress.io/guides/guides/environment-variables) that will override the default `baseUrl` set in `cypress.json`.

```json {11,12}
{
  "name": "player-tiers",
  "private": true,
  "scripts": {
    "dev": "next dev -p 3020",
    "dev:emulator": "firebase emulators:exec 'npm run dev' --import=scripts/firebase/firestore-export/ --ui",
    "build -p 3021": "next build",
    "build:emulator": "firebase emulators:exec 'npm run build' --import=scripts/firebase/firestore-export/",
    "start": "next start",
    "start:emulator": "firebase emulators:exec 'npm start' --import=scripts/firebase/firestore-export/",
    "cy:open": "cypress open",
    "cy:run": "CYPRESS_BASE_URL=http://localhost:3021 cypress run"
  }
}
```

So we use the `"cy:open"` script to run Cypress against our development environment. It allows for running individual test suites and re-running them when we change the code. The `"cy:run"` script runs against our production-like environment (ran with `"start:emulator"`). The `CYPRESS_BASE_URL` environment variable will come in handy in our Github workflow too.

## Github Actions

I switched to using [Github Actions](https://github.com/features/actions) about 2 years ago and haven't looked back. I mainly use it for Continuous Integration: unit testing, linting, type-checking, etc. But it also supports running workflows on a schedule (i.e. cron jobs), updating pull requests & issues, and so much more. There's also a huge ecosystem of open-source actions to do pretty much anything we need.

Cypress maintains the [official Cypress Github action](https://github.com/marketplace/actions/cypress-io) for running end-to-end tests in a Github workflow. **The action can handle running a build step before running the tests as well as running a local server in the background _during_ tests.** We'll definitely need both features.

```yml
name: CI

on: [push]
  # linting, type-checking, unit testing jobs

  e2e:
    name: End-to-end
    runs-on: ubuntu-latest
    container: cypress/included:7.0.1

    steps:
      - name: Checkout repo
        uses: actions/checkout@v2

      - name: Install npm dependencies
        run: npm ci

      # Setup Java for firebase CLI
      - name: Install Java
        uses: actions/setup-java@v2
        with:
          distribution: 'adopt'
          java-version: '11'

      # Run all Cypress tests in Chrome using firebase emulator
      - name: Cypress run
        uses: cypress-io/github-action@v2.9.7
        with:
          browser: chrome
          # highlight-next-line
          build: npm run build:emulator
          # highlight-next-line
          start: npm run start:emulator
        env:
          # Authorization for running the firebase CLI (emulator)
          FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}

          # Cypress variables
          # highlight-next-line
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          # highlight-next-line
          CYPRESS_BASE_URL: http://localhost:3021

          # Authorization for firebase-admin (server-side)
          FIREBASE_PROJECT_ID: player-tiers
          FIREBASE_PRIVATE_KEY:  ${{ secrets.FIREBASE_PRIVATE_KEY }}
          FIREBASE_CLIENT_EMAIL:  ${{ secrets.FIREBASE_CLIENT_EMAIL }}
          # highlight-next-line
          FIRESTORE_EMULATOR_HOST: localhost:8080

          # Authorization for firebase web API
          NEXT_PUBLIC_FIREBASE_PROJECT_ID: player-tiers
          NEXT_PUBLIC_FIREBASE_API_KEY: ${{ secrets.NEXT_PUBLIC_FIREBASE_API_KEY }}
          NEXT_PUBLIC_FIREBASE_APP_ID: ${{ secrets.NEXT_PUBLIC_FIREBASE_APP_ID }}
```

Everything comes together in the Github workflow setup. It runs every time we push a branch to `origin`. The Cypress Github action does most of the work, but we have to pass it many environment variables in order for Cypress, the Firebase client-side SDK, the Firebase server-side SDK, and the Firebase emulator to all work in this CI environment.

It seems fairly straightforward now, but when I was trying to piece it all together, it was anything but. It was the `"build:emulator"` and `"start:emulator"` scripts in the `package.json` which were the key. Before those, I was trying to run the emulator by itself in the background in order to run `"build"` and `"start"` in the foreground. It was a headache and a nightmare. 😭

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/end-to-end-testing-firebase-emulator-github-actions</link>
            <guid isPermaLink="false">end-to-end-testing-firebase-emulator-github-actions</guid>
            <category><![CDATA[firebase]]></category>
            <category><![CDATA[firestore]]></category>
            <category><![CDATA[emulator]]></category>
            <category><![CDATA[github]]></category>
            <category><![CDATA[actions]]></category>
            <category><![CDATA[nextjs]]></category>
            <category><![CDATA[cypress]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 02 May 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Using Jest mock functions in TypeScript]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/using-jest-mock-functions-typescript</link>
            <guid isPermaLink="false">using-jest-mock-functions-typescript</guid>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[jest]]></category>
            <category><![CDATA[mock]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 25 Apr 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[25 VS Code extensions for max productivity]]></title>
            <description><![CDATA[
Next week, April 29th will be [Visual Studio Code](https://code.visualstudio.com/)'s 6th birthday! 🎉 I can't remember exactly when I started using VS Code, but I believe it's been around 4 years. It started as a 2-week experiment, and I've never looked back. And I've also converted dozens of coworkers and others over to using it too. 😄

Between full-time work (in JavaScript), side projects (also in JavaScript), and even writing this post (in Markdown), **I use VS Code all the time**. So in honor of its 6th birthday I want to share the 25 VS Code extensions that I frequently use.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/25-vscode-extensions-max-productivity</link>
            <guid isPermaLink="false">25-vscode-extensions-max-productivity</guid>
            <category><![CDATA[vscode]]></category>
            <category><![CDATA[extensions]]></category>
            <category><![CDATA[productivity]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 18 Apr 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[50 shades of React rendering with Next.js]]></title>
            <description><![CDATA[
I developed my first [Next.js](https://nextjs.org/) application last November while building [Rep Yo City](https://repyo.city). I enjoyed its developer ergonomics and used it again for my most recent project, [NBA Player Tiers](https://nbaplayertiers.com). After developing and launching these two projects, it's now my go-to framework for building React applications. There are several reasons why I'm now an advocate for Next.js, including its [file-system routing](https://nextjs.org/docs/routing/introduction) and [API routes](https://nextjs.org/docs/api-routes/introduction), but I want to focus on its hybrid rendering approach.

Instead of supporting a single rendering mode for the entire app, **Next allows each page to have its own rendering mode**. This hybrid approach matches closer to the needs of our apps. There are some pages (usually landing pages) that are static and only change when we change the code. There are other pages that have content unique to a logged-in user. And even still, there are pages that are the same for all users, but change frequently.

So let's walk through the types of rendering, and see how Next.js supports it.

## Client-side rendering

With client-side rendering (aka CSR), an HTML page with a couple of `<script>` tags is sent to the browser. All data requests are made in the browser (👋🏾 [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API), [SWR](https://swr.vercel.app/) & [React Query](https://react-query.tanstack.com/)), and we render the entire UI based on that data in the browser. The majority of React applications use client-side rendering via [Create React App](https://reactjs.org/docs/create-a-new-react-app.html).

While Client-side rendering is the simplest rendering strategy, it has two drawbacks. First, the screen is initially blank while the browser loads and executes the JavaScript that will render the UI. **Second, the HTML document is also blank, which is generally worse for SEO and makes generating rich site previews (aka [unfurling](https://unfurler.com/)) more difficult or impossible.**

Next.js doesn't support rendering on the client. _Something_ is always going to be included in the page HTML. Where does that page HTML come from? We'll answer that when looking at the next rendering strategy. 😄

## Static-site generation

Static-site generation (aka SSG) is pre-rendering all pages/routes of the app at build time. As a result, **the generated HTML pages can be cached on the server (or CDN) for super-fast delivery to the browser**. And any data that the pages need to render that initial HTML are also retrieved at build time. No initial blank screen, and great for SEO and unfurling.

Next.js renders all pages using SSG by default. In Next, a page looks like a normal React component:

```js {9,16}
// src/pages/index.js

const HomePage = () => {
  const [recentShipments, setRecentShipments] = useState([])

  useEffect(() => {
    // retrieve recent shipments client-side on mount of page
    // and update the state
    getRecentShipments().then(setRecentShipments)
  })

  return (
    <div>
      <Header />
      <HeroImage />
      {recentShipments && <Shipments shipments={recentShipments} />}
      <Footer />
    </div>
  )
}

export default HomePage
```

The nice thing about SSG is that `<script>` tags are still shipped with the pre-rendered HTML. So the page can retrieve even more data on the client-side. It can be user-specific data, or data that changes often. This means that **static-site generation also supports client-side rendering after the render of the initial HTML page**. In the `HomePage` component above the header, footer and hero image are pre-rendered at build-time, while the recent shipments are rendered after the page loads in the browser.

Now if we wanted, with Next we could also retrieve the recent shipments at build time so that they are included in the initial HTML (likely to help with SEO). We export an additional `async` function called [`getStaticProps`](https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation):

```js {3,6,10-12,18,23}
// src/pages/index.js

export const getStaticProps = async () => {
  // by fetching at build time we're assuming this data
  // won't change often
  const recentShipments = await getRecentShipments()

  return {
    // `props` are passed to the page component as props
    props: {
      recentShipments,
    },
  }
}

// `recentShipments` is now passed in as a prop by the
// Next.js framework at build time
const HomePage = ({ recentShipments }) => {
  return (
    <div>
      <Header />
      <HeroImage />
      <Shipments shipments={recentShipments} />
      <Footer />
    </div>
  )
}

export default HomePage
```

If you've used [Gatsby](https://www.gatsbyjs.com/) before, Next's default SSG results in the same statically rendered pages, except how Gatsby retrieves build-time data for pages using GraphQL.

But there are two drawbacks of basic static-site generation. First off, build times can become really long when there are a lot of pages to pre-render. Think of product pages for an e-commerce site or article pages for a news site. Secondly, **if the data used to pre-render a page changes, the only way to re-render the page is to trigger a rebuild of the entire app**.

Next.js has an answer to both of these, but first let's look at another common rendering strategy.

## Server-side rendering

Server-side rendering (aka SSR) is the original approach for handling data-driven pages. [Ruby on Rails](https://rubyonrails.org/), [Flask](https://flask.palletsprojects.com/en/1.1.x/), and even [Express](https://expressjs.com/) are all web application frameworks that ultimately grab data on the server for each request and return HTML. Next.js began as a React server-side rendering framework. But now **Next encourages static-site generation over server-side rendering for performance reasons**. The time to receive the HTML document ([TTFB](https://web.dev/time-to-first-byte/)) is slower with server-side rendering because the server must compute the resultant HTML upon every request.

Next suggests fetching the data client-side unless the page not only has data that must be fetched with each request time, but also must be pre-rendered with that content. These situations are rare because per-request data needs usually come from logged-in pages that have user-specific data. But then those logged-in pages typically don't have to be pre-rendered because there are no SEO or unfurling needs.

But if server-side rendering really is needed, we can just swap `getStaticProps` for [`getServerSideProps`](https://nextjs.org/docs/basic-features/data-fetching#getserversideprops-server-side-rendering):

```js {3,7}
// src/pages/index.js

export const getServerSideProps = async () => {
  // presumably the shipments are somehow determined
  // based on the user, which is why they are retrieved
  // server-side instead of client-side or at build-time
  const recentShipments = await getRecentShipments()

  return {
    // `props` are passed to the page component as props
    props: {
      recentShipments,
    },
  }
}

// `recentShipments` is still passed in as a prop by the
// Next.js framework but at *request* time
const HomePage = ({ recentShipments }) => {
  return (
    <div>
      <Header />

      <HeroImage />

      <Shipments shipments={recentShipments} />

      <Footer />
    </div>
  )
}

export default HomePage
```

With server-side rendering, we'll always get the latest and greatest data delivered in the initial HTML. However, the main drawback is the performance. We have to ensure we have the necessary DevOps setup to handle onslaughts of traffic to the server-side rendered page. Otherwise, too many simultaneous accesses of the database or fetches of the API can bring the entire site down. Build-time rendering with cached pages is huge for performance and scale because it mitigates this problem.

## On-demand rendering

We've seen that Next.js allows for pre-rendering different pages at build time (SSG) versus rendered at request time (SSR). That flexibility is very cool but still has the drawbacks we mentioned. Enter "on-demand rendering" (I just made this up). On-demand rendering takes the best parts about static-site generation (cached pages) and combines it with the best parts about server-side rendering (dynamic pages) to create dynamic cached pages. 🤯

### Drawback: Handling too many pages to pre-render

Let's take the first drawback that we had with SSG where builds take too long when we have too many pages to pre-render. Too many pages comes from ["dynamic routes"](https://nextjs.org/docs/routing/dynamic-routes) where an object ID (like a product ID, article ID, blog post ID, etc.) are in the URL. The number of these routes can be potentially unbounded.

**To solve this, Next has this concept of ["fallback pages"](https://nextjs.org/docs/basic-features/data-fetching#fallback-pages)**. Here's how it works:

- The page is rendered at build-time without any of its data props. It's a shell page.
- Next sends that shell page to the browser for the first request of the fallback page. This is so the user gets an immediate response.
- In the background, Next fully renders the requested page just like an SSG page.
- This statically generated page is then updated on the browser.
- It's also cached with the rest of the pre-rendered pages. That way the next time it's requested, it's ready to go.

Fallback pages work with the addition of [`getStaticPaths`](https://nextjs.org/docs/basic-features/data-fetching#getstaticpaths-static-generation).

```js {5-20,29-33,49-56}
// src/pages/p/[id].js

// called at build time to figure out which product pages
// should be rendered at build time (if any)
export const getStaticPaths = async () => {
  // get the 50 most popular pages
  const popularProducts = getPopularProducts(50)

  return {
    // any paths listed here will be pre-rendered at build time
    paths: popularProducts.map((product) => ({
      params: {
        id: product.id,
      },
    })),

    // all other paths will be statically generated on-demand
    fallback: true,
  }
}

// called whenever the product page is being rendered,
// either at build time or for one-time rendering at
// request time
export const getStaticProps = async ({ params }) => {
  const product = await getProduct(params.id)

  // if no product was found (bad ID), display 404 page
  if (!product) {
    return {
      notFound: true,
    }
  }

  // pass `product` to the `ProductPage` component as props
  return {
    props: {
      product,
    },
  }
}

// `product` will be `undefined` for the initial render
// and will have a value for the full render
const ProductPage = ({ product }) => {
  return (
    <div>
      <Header />
      {!product ? (
        <Loading />
      ) : (
        <div>
          <ProductImage product={product} />
          <ProductInfo product={product} />
        </div>
      )}
      <Footer />
    </div>
  )
}

export default ProductPage
```

The `getStaticPaths` method is cool because we can decide which pages, if any, will be rendered at build time. So we can decide to pre-render the pages for the 50 most popular products by passing an array of path info objects to `paths`. And then, the thousands of other product pages will be rendered on-demand at request time.

Let's say we don't like the shell page for the on-demand pages (resulting in the need for displaying `<Loading />`). We can, instead, have the server wait to return the page HTML until it has fully rendered it that first time. **So the first request of the page will act like server-side rendering, but subsequent requests will be cached pages like static-site generation.** We do this by setting `fallback` to `'blocking'` instead of `true`.

```js {17,47-50}
// src/pages/p/[id].js

export const getStaticPaths = async () => {
  const popularProducts = getPopularProducts(50)

  return {
    // any paths listed here will be pre-rendered at build time
    paths: popularProducts.map((product) => ({
      params: {
        id: product.id,
      },
    })),

    // all other paths will be statically generated on-demand,
    // but the server will wait to return the initial HTML until
    // the page has been fully rendered
    fallback: 'blocking',
  }
}

// called whenever the product page is being rendered,
// either at build time or for one-time rendering at
// request time
export const getStaticProps = async ({ params }) => {
  const product = await getProduct(params.id)

  // if no product was found (bad ID), display 404 page
  if (!product) {
    return {
      notFound: true,
    }
  }

  // pass `product` to the `ProductPage` component as props
  return {
    props: {
      product,
    },
  }
}

// `product` will always exist
const ProductPage = ({ product }) => {
  return (
    <div>
      <Header />
      <div>
        <ProductImage product={product} />
        <ProductInfo product={product} />
      </div>
      <Footer />
    </div>
  )
}

export default ProductPage
```

The blocking fallback mode is handy when the initial page must be fully pre-rendered (for SEO or unfurlling). But keep in mind that the initial render will have a worse time-to-first-byte (TTFB).

### Drawback: Handling frequently updated data

With both the single home page route rendered at build time or the dynamic product page route rendered on-demand, we ultimately cache the rendered page. **But these pages become stale if the data used to render them updates.** Traditionally the way solve this SSG problem is to trigger an app rebuild in order to rebuild the pages. But it's fairly inefficient to rebuild the entire site because a single page has become stale.

Well, Next.js solves this problem with a feature called [Incremental Static Regeneration](https://nextjs.org/docs/basic-features/data-fetching#incremental-static-regeneration). It allows us to update _existing_ pages by re-rendering them in the background as traffic comes in. Let's revisit our `HomePage`.

```js {15}
// src/pages/index.js

const ONE_HOUR = 60 * 60 // in seconds

export const getStaticProps = async () => {
  const recentShipments = await getRecentShipments()

  return {
    props: {
      recentShipments,
    },

    // Re-generate the page on the next request
    // after at least one hour has passed
    revalidate: ONE_HOUR,
  }
}

const HomePage = ({ recentShipments }) => {
  return (
    <div>
      <Header />

      <HeroImage />

      <Shipments shipments={recentShipments} />

      <Footer />
    </div>
  )
}

export default HomePage
```

Now, the home page will be re-rendered (in the background) at most once per hour. If new shipments have happened within the last hour, the newly rendered home page will now display them. **And this is all without having to rebuild and redeploy the app.** While Next is re-rendering the page, active requests receive the currently cached page. Next returns the newly rendered page once re-rendering is complete.

**We get the benefits of frequent updates like sever-side rendering, but still with the caching benefits of static-site generation.** The database and backend load is low because a page is only re-rendered once at any given time. A thousand simultaneous requests for the same page all receive the same cached page instead of needing a thousand concurrent database reads. Huge win.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/50-shades-react-rendering-nextjs</link>
            <guid isPermaLink="false">50-shades-react-rendering-nextjs</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[ssg]]></category>
            <category><![CDATA[csr]]></category>
            <category><![CDATA[ssr]]></category>
            <category><![CDATA[nextjs]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 11 Apr 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[9 single-statement JS algorithms for common data transformations]]></title>
            <description><![CDATA[
Last month I wrote a post on a [shorthand for converting a JavaScript array into an object lookup](/blog/create-object-lookup-array-javascript-objects/). I was able to write the code in a single statement:

```js
const teamLookup = Object.fromEntries(teams.map((team) => [team.id, team]))
```

This exercise motivated me to investigate more single-statement data transformations we can use to limit our reliance on [Lodash](https://lodash.com/) (and [`.reduce()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce)). And now I'm posting about it. 😄

So here are the "rules":

1. No using Lodash (kinda the whole point)
1. No `.reduce()`. Pretty much any array or object can be transformed to another array or object within a `.reduce()` so that's no fun 😅
1. Skipping the "obvious" new ES.next functionality (like [`.find()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find), [object spread](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#spread_in_object_literals), etc)
1. No data mutations; the transformation has to generate a new object (this is necessary for [React](https://reactjs.org/) and [reducers](https://reactjs.org/docs/hooks-reference.html#usereducer))

Now that we've gotten that out of the way let's look at our transformations.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/9-single-statement-javascript-algorithms-common-data-transformations</link>
            <guid isPermaLink="false">9-single-statement-javascript-algorithms-common-data-transformations</guid>
            <category><![CDATA[lodash]]></category>
            <category><![CDATA[algorithms]]></category>
            <category><![CDATA[objects]]></category>
            <category><![CDATA[arrays]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 04 Apr 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Quickie fetch timeout]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/quickie-fetch-timeout</link>
            <guid isPermaLink="false">quickie-fetch-timeout</guid>
            <category><![CDATA[fetch]]></category>
            <category><![CDATA[timeout]]></category>
            <category><![CDATA[promises]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 28 Mar 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Copy to clipboard React custom Hook]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/copy-to-clipboard-react-custom-hook</link>
            <guid isPermaLink="false">copy-to-clipboard-react-custom-hook</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[hooks]]></category>
            <category><![CDATA[clipboard]]></category>
            <category><![CDATA[web]]></category>
            <category><![CDATA[apis]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 21 Mar 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Create an object lookup from an array of JavaScript objects]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/create-object-lookup-array-javascript-objects</link>
            <guid isPermaLink="false">create-object-lookup-array-javascript-objects</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[esnext]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 14 Mar 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Auto-generate React PropTypes from TypeScript components]]></title>
            <description><![CDATA[
One of the reasons I enjoy writing React in TypeScript is using static types for component props. In addition to defining the [basic types](/blog/react-prop-types-with-typescript/), we can also define more complex situations like [conditional props](/blog/conditional-react-props-typescript/), [polymorphic components](/blog/polymorphic-react-components-typescript/), and [generic components](/blog/generic-react-components-typescript/). If an app uses a component incorrectly, the app will fail to type check until the code is fixed. The best part is that we can find these issues statically (potentially within our editor), without having to use the app.

React [PropTypes](https://reactjs.org/docs/typechecking-with-proptypes.html), on the other hand, are run-time checks which require us to run the app either in the browser or in unit tests. In a TypeScript app, PropTypes aren't really necessary. However, **a shareable component library written in TypeScript may need PropTypes if some of its consuming apps are still written in vanilla JavaScript**.

So here is a helper function that:

- Given a generated TypeScript definition file (`*.d.ts`) for a component
- And given the component's generated/transpiled JavaScript file
- Adds React PropTypes to the JavaScript file based on those TypeScript definitions

```typescript
import { readFile, writeFile } from 'fs-extra'
import {
  loadConfig,
  createProgram,
  parseFromProgram,
  inject,
} from 'typescript-to-proptypes'

const TS_CONFIG = loadConfig(/* path to tsconfig.json */)

type Result = 'success' | 'failed' | 'not-component'

interface Options {
  tsDefFilePath: string
  jsFilePath: string
  tsProgram: ReturnType<typeof createProgram> // 👈🏾 TS utility type
}

const generatePropTypes = async ({
  tsDefFilePath,
  jsFilePath,
  tsProgram,
}: Options): Promise<Result> => {
  // `parseFromProgram` retrieves the TS defs for the props,
  // and returns an AST representation of the React Prop Types
  const propTypesAST = parseFromProgram(tsDefFilePath, tsProgram, {
    checkDeclarations: true,
  })

  // if the AST is empty, there are no prop types,
  // which must mean it's not a component
  if (!propTypes.body.length) {
    return 'not-component'
  }

  const jsFileContent = await readFile(jsFilePath, 'utf8')

  // `inject` parses the JS file into an AST & inserts
  // the PropTypes AST based on specified options
  const jsFileContentWithPropTypes = inject(propTypesAST, jsFileContent, {
    removeExistingPropTypes: true,
    babelOptions: {
      filename: jsFilePath,
    },
    comment: `
=============== WARNING ================
| These PropTypes are auto-generated   |
| from the TypeScript type definitions |
========================================
    `,
    reconcilePropTypes: (prop, previous, generated) => {
      if (previous !== undefined) {
        const usedCustomValidator = !previous.startsWith('PropTypes')
        const ignoreGenerated = previous.startsWith(
          'PropTypes /* @typescript-to-proptypes-ignore */',
        )

        if (usedCustomValidator || ignoreGenerated) {
          return previous
        }
      }

      return generated
    },

    // include prop type if it's the children prop or if it has a
    // jsDoc description. this helps avoid pulling in prop types
    // for components inheriting base elements like `<a>` or `<input>`
    shouldInclude: ({ prop }) => prop.name === 'children' || !!prop.jsDoc,
  })

  if (!jsFileContentWithPropTypes) {
    return 'failed'
  }

  // OPTIONAL: Use prettier on `jsFileContentWithPropTypes`

  await writeFile(jsFilePath, jsFileContentWithPropTypes)

  return 'success'
}

// `createProgram` comes from the TS Compile API
// create a program passing an array of all the `.d.ts` files for components
// const program = createProgram(tsDefFilePaths, TS_CONFIG)

// The function also assumes that the JS files for the components have
// already been generated/transpiled. Depending on your setup, you would
// use the `babel` or `tsc` CLIs.
```

If you're using TypeScript with Babel via [`@babel/preset-typescript`](https://babeljs.io/docs/en/babel-preset-typescript), you can use the [`babel` CLI](https://babeljs.io/docs/en/babel-cli) to generate/transpile JavaScript files:

```bash
NODE_ENV=production babel src --extensions '.ts,.tsx,.js,.jsx' --out-dir lib
```

And you can generate declaration files for your components using the [`tsc` CLI](https://www.typescriptlang.org/docs/handbook/compiler-options.html):

```bash
tsc --declaration --declarationDir lib/types --emitDeclarationOnly --project tsconfig.json
```

Hopefully, that gets you your answer. I searched and searched, trying to find something like this. Ultimately I had to adapt code from a script deep in the bowels of the [Material-UI](https://material-ui.com/) codebase. If you're interested in some more details, feel free to read on. Otherwise, thanks for reading! 😄

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/auto-generate-react-prop-types-typescript-components</link>
            <guid isPermaLink="false">auto-generate-react-prop-types-typescript-components</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[designSystem]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 07 Mar 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Sync to localStorage with React useReducer Hook]]></title>
            <description><![CDATA[
In my last post on [React custom Hooks vs. Mixins](/blog/react-custom-hooks-mixins/), I compared a custom Hook I recently wrote with its equivalent in Mixins form. In this post now, I want to share a [`useReducer`](https://reactjs.org/docs/hooks-reference.html#usereducer) + [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) custom Hook I needed to synchronize my reducer state to `localStorage`.

I Googled around for "useReducer localStorage" for the best approach to this and was surprised to find very little answers. I also wanted to be able to use the [`useLocalStorage`](https://github.com/streamich/react-use/blob/master/docs/useLocalStorage.md) Hook from [`react-use`](https://github.com/streamich/react-use) to handle the `localStorage` piece.

After coalescing different blog posts and StackOverflow answers, I came up with this `usePersistReducer` Hook:

```js
import { useCallback, useReducer } from 'react'
import { useLocalStorage } from 'react-use'

const LOCAL_STORAGE_KEY = 'KEY_GOES_HERE'

const INITIAL_STATE = {
  // initial state
}

const reducer = (state, action) => {
  // return updated state based on `action.type`
}

const usePersistReducer = () => {
  // grab saved value from `localStorage` and
  // a function to update it. if
  // no value is retrieved, use `INITIAL_STATE`
  const [savedState, saveState] = useLocalStorage(
    LOCAL_STORAGE_KEY,
    INITIAL_STATE,
  )

  // wrap `reducer` with a memoized function that
  // syncs the `newState` to `localStorage` before
  // returning `newState`. memoizing is important!
  const reducerLocalStorage = useCallback(
    (state, action) => {
      const newState = reducer(state, action)

      saveState(newState)

      return newState
    },
    [saveState],
  )

  // use wrapped reducer and the saved value from
  // `localStorage` as params to `useReducer`.
  // this will return `[state, dispatch]`
  return useReducer(reducerLocalStorage, savedState)
}

const Example = () => {
  // return value from `usePersistReducer` is identical
  // to `useReducer`
  const [state, dispatch] = usePersistReducer()

  // render UI based on `state`
  // call `dispatch` based on user actions
}
```

> I like to create custom Hooks, even if I'm using them in one place, to encapsulate logic together. It's nice to give a name to multiple Hooks used together. Here, I'm using `usePersistReducer` solely to wrap this particular `reducer` so it doesn't take any parameters. But if I wanted to make `usePersistReducer` a more reusable custom Hook, it would probably take a `reducer`, `storageKey`, and `initialState` as parameters.

And that's it! If all you were looking for was an answer, you don't need to read any further. But if you're interested in more details, by all means keep reading. 😄

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/sync-localstorage-react-usereducer-hook</link>
            <guid isPermaLink="false">sync-localstorage-react-usereducer-hook</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[hooks]]></category>
            <category><![CDATA[localStorage]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 28 Feb 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[React custom Hooks vs. Mixins]]></title>
            <description><![CDATA[
The last couple of weeks, I've been working on my latest project, [NBA Player Tiers](https://nbaplayertiers.com/) (very much still in-progress). I wrote this custom Hook to retrieve NBA player information from a [Firestore](https://firebase.google.com/products/firestore) DB. It's composed of other custom Hooks and it just makes me giddy.

```js {15,22}
import { useEffect, useState } from 'react'
import { usePromise as useSafeAsync } from 'react-use'

const getAllPlayers = async () => {
  // makes a Firebase request to Firestore
  // and returns a Promise with an array
  // of Player objects
}

const usePlayers = () => {
  const safeAsync = useSafeAsync()
  const [allPlayers, setAllPlayers] = useState([])

  useEffect(() => {
    safeAsync(getAllPlayers()).then(setAllPlayers)
  }, [safeAsync])

  return allPlayers
}

const PlayerPicker = () => {
  const players = usePlayers()

  // render players UI using `players`
}
```

> The [`usePromise`](https://github.com/streamich/react-use/blob/master/docs/usePromise.md) custom Hook from [`react-use`](https://github.com/streamich/react-use) (which I've renamed to `useSafeAsync`) returns a helper function. That function takes a `Promise` and will only resolve it when the component is mounted. If the component is unmounted, the `Promise` will not resolve. It's a safer way to do async within React components. If you're interested in the rationale behind this, read my earlier post called [Handling async React component effects after unmount](/blog/handling-async-react-component-effects-after-unmount/).

This `usePlayers` custom Hook is an extraction of the Firestore side effect request and state management. I use `usePlayers()` as if it's a regular helper method but the `PlayerPicker` component will re-render when the async data returns because `usePlayers` updates the component's state.

React has always been great at sharing UIs through its component model. And we can easily reuse traditional helper functions by importing them. **But abstracting and sharing stateful, non-visual logic had always been in a challenge in React prior to custom Hooks.**

Then the other day I saw this tweet from [Mark Dalgleish](https://twitter.com/markdalgleish) that brought back nostalgia:

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Whoa, remember React mixins? I forgot about that.</p>&mdash; Mark Dalgleish (@markdalgleish) <a href="https://twitter.com/markdalgleish/status/1362609665880727562?ref_src=twsrc%5Etfw">February 19, 2021</a></blockquote>

We used to share stateful, non-visual logic with Mixins. But Mixins were dropped 4 years ago with the [release of React 15.5](https://reactjs.org/blog/2017/04/07/react-v15.5.0.html) and had fallen out of favor nearly [2 years prior](https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750). **It's likely that there are many React developers who don't know much about Mixins at this point.**

So I want to take a quick look walk down memory lane at Mixins to see how surprisingly similar they are to custom Hooks. Mixins just had more gnarly gotchas.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/react-custom-hooks-mixins</link>
            <guid isPermaLink="false">react-custom-hooks-mixins</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[hooks]]></category>
            <category><![CDATA[mixins]]></category>
            <category><![CDATA[HOCs]]></category>
            <category><![CDATA[RenderProps]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 21 Feb 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[5 tips for a healthier DivOps setup]]></title>
            <description><![CDATA[
[DivOps](https://www.divops.dev/), probably more commonly known as Frontend Infrastructure, is all of the tooling needed to set up, maintain, and deploy a modern frontend application. So we're talking [Webpack](https://webpack.js.org/), [Babel](https://babeljs.io/), [PostCSS](https://postcss.org/), [Prettier](https://prettier.io/), [TypeScript](https://www.typescriptlang.org/), [ESLint](https://eslint.org/), [Jest](https://jestjs.io/), [Cypress](https://www.cypress.io/), and many many more. They, in addition to the actual code, are what make up our frontend apps.

The latter tools in that list (TypeScript, ESLint, Jest, etc.) help us catch bugs in our code. **They are code validators.** But since they are code as well, we can make mistakes in them too. And as our codebase grows, team members with less JavaScript experience are more likely to make contributions and, unfortunately, also make mistakes.

In my opinion, a codebase with false-positive tests or tests that generate warnings is unhealthy. And this can quickly snowball. I mean, once there are a couple of test warnings or ESLint warnings or React warnings, what's one more, right? **What we need to keep our codebase healthy are code validators of the code validators.** 🤯 And let's make robots handle this. Relying on best practice documentation or human review likely won't get it done.

The rest of this post walks through 5 DivOps configurations I use to help prevent my team (including me) from shipping poor code validation code.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/5-tips-healthier-divops-setup</link>
            <guid isPermaLink="false">5-tips-healthier-divops-setup</guid>
            <category><![CDATA[divops]]></category>
            <category><![CDATA[testing]]></category>
            <category><![CDATA[eslint]]></category>
            <category><![CDATA[jest]]></category>
            <category><![CDATA[typescript]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 14 Feb 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[8 helpful custom React Hooks]]></title>
            <description><![CDATA[
Custom React Hooks allow us to extract component logic into reusable functions. Custom Hooks look very much like normal helper functions, except they can maintain component state and perform effects. There are many common actions that we do in our React applications that can be wrapped up in a custom Hook.

So let's take a look at the implementations of 8 different custom Hooks. Each implementation will include code comments as well as a potential use case. And since I'm a TypeScript fan, I'll also provide a second implementation in TypeScript when there is any TypeScript uniqueness. 😄

You'll find flavors of many of these custom Hooks in the [`react-use`](https://github.com/streamich/react-use) package. So if you find yourself using a lot of these Hooks, you might as well import the package.

Let's jump in!

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/8-helpful-custom-react-hooks</link>
            <guid isPermaLink="false">8-helpful-custom-react-hooks</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[hooks]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 07 Feb 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Prettier + ESLint = ❤️]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/prettier-eslint</link>
            <guid isPermaLink="false">prettier-eslint</guid>
            <category><![CDATA[divops]]></category>
            <category><![CDATA[githooks]]></category>
            <category><![CDATA[vscode]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 31 Jan 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Handling async React component effects after unmount]]></title>
            <description><![CDATA[
Have you ever gotten this warning while developing React components?

```
Warning: Can't perform a React state update on an unmounted component.
This is a no-op, but it indicates a memory leak in your application.
To fix, cancel all subscriptions and asynchronous tasks in a
useEffect cleanup function.
```

This occurs when we try to update the state of a React component after it has been unmounted and removed from the component tree. And that is usually the result of making an async request (usually a data fetch), **but before the response is received and the data is stored in component state, the component has already been unmounted**.

I typically see these warnings during my Jest unit test runs (with [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/)). Of course I mock out my `fetch` requests. But if I have a test run that just cares about the initial render, the test finishes and unmounts the test component before the mocked async action finishes.

It can be frustrating because it seems to never happen in our development environments and only tests, which aren't real speed use cases. But I believe the tests may be exposing potential production issues. **There are lots of variables that can cause a `fetch` request to be slower than expected**, so if the UI unmounts before the response returns, our users can find themselves in this situation.

Typically this won't break our apps because React will just ignore our state update function call, but this is still a warning that we want to prevent from happening. So how do we do that? How do we prevent it?

First lets look at a sample "app" that causes this error.

```js {7,24}
import { useState, useEffect } from 'react'

const Results = () => {
  const [items, setItems] = useState([])

  useEffect(() => {
    fetchItems().then(setItems)
  }, [])

  return (
    <ol>
      {items.map((item) => (
        <li key={item}>{item}</li>
      ))}
    </ol>
  )
}

const App = () => {
  const [shown, setShown] = useState(false)

  return (
    <div>
      {shown && <Results />}
      <button onClick={() => setShown((curShown) => !curShown)}>
        {shown ? 'Hide' : 'Show'}
      </button>
    </div>
  )
}
```

[Try on CodeSandbox](https://codesandbox.io/s/elastic-knuth-eb1ly?file=/src/App.js)

In the example app, `<Results />` is rendered based upon the toggle state of the button. When the button is toggled off (using the [functional update](https://reactjs.org/docs/hooks-reference.html#functional-updates) form), `<Results />` is unmounted.

The `Results` component itself, asynchronously fetches items, and then calls `setItems` (the state updater) when the data comes back. **Now, if the button is toggled off after the call to `fetchItems`, but before the fetched data has returned, it will be unmounted when `setItems` called.** And that generates the warning. Try it out and click the button quickly. You'll see the warning in the CodeSandbox console.

Now let's get into the options for fixing.

## Option 1 - Variable to track mounted state

Vanilla [JavaScript Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) do not have the ability to be cancelled. So the next best alternative to avoid the React warning is to **not call the state updater if the component has been unmounted**. And in order to do _that_ we need to keep track of the mounted state.

This can be done inline in the same `useEffect` call in which we're making our `fetch` request.

```js {7,10,15-17}
import { useState, useEffect } from 'react'

const Results = () => {
  const [items, setItems] = useState([])

  useEffect(() => {
    let mounted = true

    fetchItems().then((newItems) => {
      if (mounted) {
        setItems(newItems)
      }
    })

    return () => {
      mounted = false
    }
  }, [])

  // render UI
}
```

The `mounted` variable is initialized to `true` and then set to `false` in the [clean-up function](https://reactjs.org/docs/hooks-reference.html#cleaning-up-an-effect) returned by `useEffect`. That's how the mounted state is maintained. Then when the promise from `fetchItems()` resolves, we check to see if `mounted` is still `true`. If so, we'll call `setItems` with the new data. Otherwise, we'll do nothing. It's basically what React would do, but without the warning.

This local variable approach only works within a single `useEffect` call without any dependencies. It will not work across multiple `useEffect` calls within a component. It also isn't suitable for a `useEffect` call that has dependencies because the mounted state will be reset even though the component itself hasn't been unmounted.

## Option 2 - Ref to track mounted state

If we need to track the mounted state in multiple `useEffect` calls within a component, we can use a [ref](https://reactjs.org/docs/hooks-reference.html#useref) to maintain the mounted state across component re-renders.

```js {5,7-14,18}
import { useState, useEffect, useRef } from 'react'

const Results = () => {
  const [items, setItems] = useState([])
  const mountedRef = useRef(false)

  // effect just for tracking mounted state
  useEffect(() => {
    mountedRef.current = true

    return () => {
      mountedRef.current = false
    }
  }, [])

  useEffect(() => {
    fetchItems().then((newItems) => {
      if (mountedRef.current) {
        setItems(newItems)
      }
    })
  }, [])

  useEffect(() => {
    // another fetch request for data
    // that will use `mountedRef.current`
  }, [])

  // render UI
}
```

The first `useEffect` call maintains the state with the `mountedRef`. It's set to `true` when the effect is first run and it's set to `false` when the component unmounts. Because the `useEffect` call has `[]` as its dependencies, it'll never run again when the `Results` component is re-rendered. But the `mountedRef` will continue to keep the mounted state across re-renders.

**Now, any other async effects can check the mounted state before calling state updaters because the ref is available everywhere within the component.**

## Option 3 - Custom Hook to track mounted state

If we need to track the mounted state in a number of different components, this is the perfect case to create a [custom Hook](https://reactjs.org/docs/hooks-custom.html). We basically want to move the logic from Option 2 into a custom Hook.

```js {7,17,22,26,30}
import { useState, useEffect, useRef, useCallback } from 'react'

// returns a function that when called will
// return `true` if the component is mounted
const useMountedState = () => {
  const mountedRef = useRef(false)
  const isMounted = useCallback(() => mountedRef.current, [])

  useEffect(() => {
    mountedRef.current = true

    return () => {
      mountedRef.current = false
    }
  }, [])

  return isMounted
}

const Results = () => {
  const [items, setItems] = useState([])
  const isMounted = useMountedState()

  useEffect(() => {
    fetchItems().then((newItems) => {
      if (isMounted()) {
        setItems(newItems)
      }
    })
  }, [isMounted])

  // render UI
}
```

The `useMountedState` custom Hook uses the same ref to maintain the mounted state. However, it returns a function that when called returns the value of the ref. It leverages [`useCallback`](https://reactjs.org/docs/hooks-reference.html#usecallback) so that we don't recreate a new function every time `useMountedState` is called for every re-render of `Results`.

**Now, `useMountedState` can be called in any component, like `Results`, that needs to keep track of the mounted state.** And the `isMounted` function can be called multiple times within a given component as well.

Notice that the `isMounted` function becomes a new dependency for the `useEffect` call fetching the data. This is why it was important that `useMountedState` used `useCallback` to memoize the function. Otherwise, the fetch would be called with every re-render of `Results` because the function would be newly created with each re-render. For more details, read my post on [helper functions in the React `useEffect` Hook](/blog/helper-functions-react-useeffect-hook/).

By the way, the awesome [`react-use`](https://github.com/streamich/react-use) package (that contains every custom Hook imaginable) has the same [`useMountedState`](https://github.com/streamich/react-use/blob/master/docs/useMountedState.md) custom Hook.

## Option 4 - Custom Hook to fetch only when mounted

The previous three approaches provided us with a mounted state to do whatever we wished. But we were only using it in conjunction with making an async fetch request. So what if we created a custom Hook that specifically was for restricting async actions to the mounted state?

```js {3-11,18,21-22}
const useSafeAsync = () => {
  const isMounted = useMountedState()
  const safeAsync = useCallback((promise) => {
    return new Promise((resolve) => {
      promise.then((value) => {
        if (isMounted()) {
          resolve(value)
        }
      })
    })
  })

  return safeAsync
}

const Results = () => {
  const [items, setItems] = useState([])
  const safeAsync = useSafeAsync()

  useEffect(() => {
    safeAsync(fetchItems()).then(setItems)
  }, [safeAsync])

  // render UI
}
```

Our `useSafeAsync` custom Hook is an abstraction of checking the mounted state after resolving a `Promise`. It makes use of the same `useMountedState` custom Hook to keep track of the mounted state and returns a function (`safeAsync`) that will take the `Promise` object returned from the async action. When that promise resolves, it verifies that the component is still mounted before passing along the resolution.

So now in our `Results` component, the code is very similar to the initial simple (but broken) code. **The only difference is we wrap the return value of `fetchItems()` in `safeAsync` so that we can know that anything we do afterward will happen when `Results` is still mounted.**

Notice this time, that `safeAsync` is listed as the dependencies of `useEffect`. That's why it's key that `useSafeAsync` uses `useCallback` to memoize the function it returns.

Once again, `react-use` has a similar custom Hook that it calls [`usePromise`](https://github.com/streamich/react-use/blob/master/docs/usePromise.md). It also handles promise rejection as well. [React Query](https://react-query.tanstack.com/), a library for fetching, caching and updating data, also has a [similar API](https://react-query.tanstack.com/guides/queries) while providing loads of additional functionality. If you're looking for a lower-level wrapper over the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API), but is still "safe", check out [`useFetch`](https://use-http.com/#/?id=basic-usage-auto-managed-state) from the [`use-http`](https://use-http.com/) package.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/handling-async-react-component-effects-after-unmount</link>
            <guid isPermaLink="false">handling-async-react-component-effects-after-unmount</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[hooks]]></category>
            <category><![CDATA[async]]></category>
            <category><![CDATA[effects]]></category>
            <category><![CDATA[unmount]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 24 Jan 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Use cases for TypeScript const assertions]]></title>
            <description><![CDATA[
Have you ever run into a problem where TypeScript incorrectly infers the types of properties of an object? And then when you try to pass a piece (or all) of it to a function it's a type error? Usually this happens to me because of ["literal type widening"](https://mariusschulz.com/blog/literal-type-widening-in-typescript) of [union string literal types](https://www.typescriptlang.org/docs/handbook/literal-types.html#string-literal-types) within object literal declarations.

Phew, that was a lot of technical terms. 😅 Let's ground ourselves with an example:

```typescript {9,18}
const notify = (
  data: unknown,
  {
    sport,
    level,
  }: {
    sport: string
    // 👇🏾 union string literal
    level: 'player' | 'team' | 'sport' | 'all'
  },
) => {
  // notify data
}

const DEFAULT_NBA_OPTIONS = {
  sport: 'nba',
  // 👇🏾 trying to use one of the literals in the union
  level: 'team',
}

notify('James Harden traded to the Nets 😢', DEFAULT_NBA_OPTIONS)
// ❌ TS Error!
// Argument of type '{ sport: string; level: string; }'
// is not assignable to parameter of type
// '{ sport: string; level: "all" | "player" | "team" | "sport"; }'.
//  Types of property 'level' are incompatible.
//    Type 'string' is not assignable to type
//    '"all" | "player" | "team" | "sport"'.
```

> Curious about the use of `unknown`? Read [When to use TypeScript `unknown` vs `any`](/blog/when-use-typescript-unknown-versus-any/).

The problem is that even though we defined `DEFAULT_NBA_OPTIONS` with a `level` of `'team'`, when the object gets passed to `notify()` the type of `level` is `string` which can't be assigned to the string union type `'player' | 'team' | 'sport' | 'all'`. Interestingly enough, if we pass the object inline, it works:

```typescript {3}
notify('James Harden traded to the Nets 😢', {
  sport: 'nba',
  level: 'team',
})
// 👍🏾 No error
```

This works because the type of `level` is now the string literal `'team'` which _is_ assignable to our string union type.

Now there are several ways we could fix this type error, including creating a `NotifyOptions` type which we would define as the type of the second parameter of `notify()`, as well as the type of `DEFAULT_NBA_OPTIONS`. But let's say we don't want to (or can't) do that. One way we can solve it is by using a [const assertion](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions):

```typescript {4}
const DEFAULT_NBA_OPTIONS = {
  sport: 'nba',
  level: 'team',
} as const

notify('James Harden traded to the Nets 😢', DEFAULT_NBA_OPTIONS)
```

The const assertion takes the type of `DEFAULT_NBA_OPTIONS` from being:

```typescript
{
  sport: string
  level: string
}
```

to:

```typescript
{
  readonly sport: "nba"
  readonly level: "team"
}
```

The type of `DEFAULT_NBA_OPTIONS.level` is now the literal `'team'` just like when we passed it inline. And because `'team'` is assignable to our string union type, everything works swimmingly. And the const assertion also makes the properties of `DEFAULT_NBA_OPTIONS` read-only so that they cannot be changed.

So why is the const assertion necessary? Why weren't the types of `sport` and `level` the specific literals, `'nba'` and `'team'`, instead of the more general `string` type? Well, **by default TypeScript performs what's called ["literal type widening"](https://mariusschulz.com/blog/literal-type-widening-in-typescript) for objects**. That way when we define an object, we can change a property like we would expect:

```typescript
const player = {
  name: 'James Harden',
  team: 'Houston Rockets',
}

// not a type error
// (as a Rockets fan, I wish it was)
player.team = 'Brooklyn Nets' // 😢
```

**So with the const assertion we're telling TypeScript not to widen any literal types, but have the types match their literal values.**

Another cool use of [const assertions](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions) is with [React custom Hooks](https://reactjs.org/docs/hooks-custom.html). Typically when a custom Hook returns 2 values, we return it using an array tuple (just like the [`useState` Hook](https://reactjs.org/docs/hooks-state.html)):

```typescript {15}
const useUserSearch = () => {
  const [username, setUsername] = useState('')
  const [user, setUser] = useState<User | null>(null)

  useEffect(() => {
    if (username) {
      getUserApi(username).then(setUser)
    } else {
      setUser(null)
    }
  }, [username])

  // use const assertion for the correct return type
  // User first, function second
  return [user, setUsername] as const
}
```

Without the const assertion, the inferred return type of `useUserSearch` would be:

```typescript
(User | ((username: string) => void))[]
```

Translation: an array of `string` or `(username: string) => void` types in any order. It could be an array of 0 or 100 items. The first item can be the function or all items could be. But that's not what we want. We specifically want a "tuple" where the first item is a `User` and the second item is the function. With the const assertion, the type is now:

```typescript
readonly [User, (username: string) => void]
```

The order is correct, the length is fixed, and the array is read-only. 🎉

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/use-cases-typescript-const-assertions</link>
            <guid isPermaLink="false">use-cases-typescript-const-assertions</guid>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[constAssertions]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[hooks]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 17 Jan 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[When to use TypeScript unknown vs any]]></title>
            <description><![CDATA[
I try to be as strict as possible when I use TypeScript. I always turn on the [`strict` option](https://www.typescriptlang.org/tsconfig#strict) in my `tsconfig.json` file to receive stronger guarantees of program correctness. When I'm migrating an app over to TypeScript, I will enable the [`allowJS` option](https://www.typescriptlang.org/tsconfig#allowJs), but within a given file I'm all-TS or nothing.

In my opinion, **there's no point of opting in to the extra work of type-checking if I'm not going to be strict about it**. Others feel differently about it, which is perfectly fine, but this is how I roll. 😎 I also enable a bunch of ESLint rules for TypeScript using the [`@typescript-eslint/eslint-plugin`](https://github.com/typescript-eslint/typescript-eslint), particularly the [`typescript-eslint/no-explicit-any`](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-explicit-any.md) rule that warns when the [`any`](https://www.typescriptlang.org/docs/handbook/basic-types.html#any) type is explicitly used.

But **there are legitimate situations where we don't know the type of a value being passed into a function**. Usually it's some pass-through interface that takes arbitrary data, but there are other use cases as well. In these situations, we can use the TypeScript [`unknown`](https://www.typescriptlang.org/docs/handbook/basic-types.html#unknown) type.

```typescript {3,13}
const postJSON = (
  url: string,
  data: unknown,
  options: PostOptions = {},
): Promise<Response> => {
  return window.fetch(url, {
    ...options,
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      ...options.headers,
    },
    body: JSON.stringify(data),
  })
}
```

Before I knew about `unknown`, I would reluctantly use the catch-all `any` type (and disable `no-explicit-any` for that line 😔). But with the `unknown` type, we can pretty much avoid all cases where we use to reach for `any`. Both `unknown` and `any` are used when we don't know the type of a value, but they have technical and semantic differences.

**With an `unknown` type we cannot reassign it to a different type, manipulate it, or pass it to another function that has a specified type:**

```typescript
const numberData: number = unknownData
// ❌ Type 'unknown' is not assignable
// to type 'number'.

const stringData = unknownData.toString()
// ❌ Object is of type 'unknown'.

const dataKeys = Object.keys(unknownData)
// ❌ Argument of type 'unknown' is not
// assignable to parameter of type 'object'.

const dataBool = unknownData as boolean
// ⚠️ Type assertions workaround typing
// but could result in runtime issues
```

> The reason why we were able to pass `data` to [`JSON.stringify()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) is because the type of the value it accepts is actually `any`. An `unknown` value can be passed to an `any` type.

However, if we use type narrowing, like doing `typeof`/`instanceof` checks, comparison checks, or [user-defined type guards](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards), then we can assign an `unknown` type to a specific type.

```typescript
// typeof check
if (unknownData && typeof unknownData === 'object') {
  // ✅ TS knows `data` is an `object`
  // type now
  const dataKeys = Object.keys(unknownData)
}

// comparison check
if (unknownData === 'Rockets') {
  // ✅ TS knows `data` is a `string`
  // type now
  const firstChar = unknownData.charAt(0)
}

// user-defined type guard
const isProduct = (item: unknown): item is Product => {
  // ✅ Although we use type assertion, we are
  // doing validation first
  return !!(item as Product)?.id
}
```

> User-defined type guards are a topic in and of themselves, which I don't want to dive into right now. But if you're interested in how they can be applied, check out my post [Filtering undefined elements from an array in TypeScript](/blog/filtering-undefined-elements-from-array-typescript/).

The `any` type on the other hand allows us to do anything with a value including access arbitrary properties, even ones that don't exist. We're basically reverting back to plain ol' JavaScript at this point.

```typescript
const numberData: number = anyData
// 😨 No error

const stringData = anyData.toString()
// 😨 No error calling `.toString()`

const dataKeys = Object.keys(anyData)
// 😨 No error, let's hope `anyData`
// is an `object`
```

The `any` type is definitely the easier type to deal with because we get back to the flexibility of "we know what we're doing" JavaScript. But like I said in the beginning, I try to avoid being in that world when writing TypeScript because what's the point?

Outside of the technical differences between `unknown` and `any`, to me there are also some semantic differences as well. Let's revisit the `postJSON` example from the beginning:

```typescript {3,13}
const postJSON = (
  url: string,
  data: unknown,
  options: PostOptions = {},
): Promise<Response> => {
  return window.fetch(url, {
    ...options,
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      ...options.headers,
    },
    body: JSON.stringify(data),
  })
}
```

If we swapped out `unknown` for `any` as the type for `data`, it won't make any technical difference from a type safety standpoint. All we're doing is calling `JSON.stringify()` on the value, and `JSON.stringify()` accepts an `any` value.

But when I'm reading code that uses `unknown`, it says to me "I don't know the type of this value and it doesn't even matter because it's just a middleman." It's a very intentional type, just like picking `string`, `number` or a custom interface.

Whereas to me, seeing the `any` type signals either an inability to figure out the type or figuring out the type would require an unnecessary amount of effort. Using `any` is sometimes unavoidable though. I try not to be dogmatic. But more times that not I've found that **when my code is hard to type, it's because it's unnecessarily complex**. Simplifying it so that TypeScript can understand has the added benefit of simplifying it so that my coworkers (including future me) can understand it as well.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/when-use-typescript-unknown-versus-any</link>
            <guid isPermaLink="false">when-use-typescript-unknown-versus-any</guid>
            <category><![CDATA[types]]></category>
            <category><![CDATA[unknown]]></category>
            <category><![CDATA[any]]></category>
            <category><![CDATA[typeSafety]]></category>
            <category><![CDATA[typeChecking]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 10 Jan 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Object & array dependencies in the React useEffect Hook]]></title>
            <description><![CDATA[
Happy 2021! 🎉

Back in October, I gave four options for dealing with [helper functions](/blog/helper-functions-react-useeffect-hook/) listed as dependencies in the React [`useEffect` Hook](https://reactjs.org/docs/hooks-reference.html#useeffect). I promised to share other gotchas around `useEffect` dependencies in follow-up posts. So now I want to give four more options, but this time dealing with objects or arrays in dependencies.

Let's quickly recap the `useEffect` Hook in React. By default it runs on every re-render:

```js {4-6}
const Example = () => {
  const [count, setCount] = useState(0)

  useEffect(() => {
    document.title = `You clicked ${count} times`
  })

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  )
}
```

However, we rarely want this functionality because it's likely that the effect will run more times than it really needs to. The `useEffect` hook takes a second parameter, a "dependencies" array, **that will only re-run the effect when the values within the array change across re-renders**. This allows us to optimize how many times the effect is run.

```js {6}
const Example = () => {
  const [count, setCount] = useState(0)

  useEffect(() => {
    document.title = `You clicked ${count} times`
  }, [count]) // Only re-run the effect if count changes

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  )
}
```

This works perfectly fine when we're using primitive values like booleans, numbers, and strings. But complex values like objects, arrays, and functions pose a challenge because React uses "referential equality" for these complex values within the dependencies array.

React checks to see if the object in the current render points to the same object in the previous render. **The objects have to be the exact same object in order for `useEffect` to skip running the effect.** So even if the contents are the exact same, if a new object is created for the subsequent render, `useEffect` will re-run the effect.

I've already discussed dealing with [helper functions](/blog/helper-functions-react-useeffect-hook/) in the previous post, so in this post I want to focus on options we have when dealing with objects or arrays as `useEffect` dependencies.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/object-array-dependencies-react-useEffect-hook</link>
            <guid isPermaLink="false">object-array-dependencies-react-useEffect-hook</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[hooks]]></category>
            <category><![CDATA[customHooks]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 03 Jan 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Conditional React Hooks]]></title>
            <description><![CDATA[
Hooks launched in React with [v16.8](https://reactjs.org/blog/2019/02/06/react-v16.8.0.html) nearly 2 years ago, enabling us to use state and other React features without writing a class. After getting a handle of Hooks, I've found Hooks-based components to be more approachable than their class-based counterparts. This has been the same in my minishops as well. Those taking the [Zero to React with Hooks Minishop](/minishops/zero-to-react-with-hooks/) seem to pick up Hooks faster than those in the [Migrating to React Hooks Minishop](/minishops/migrating-to-react-hooks/).

But no matter how good an abstraction is, there are always [abstraction leaks](https://en.wikipedia.org/wiki/Leaky_abstraction) and it's no different with React Hooks. I alluded to one in my post on dealing with [helper functions in the `useEffect` Hook](/blog/helper-functions-react-useeffect-hook/). Another one of those leaks is that **we can only call Hooks at the top level of our React function components**.

We can't call Hooks inside of conditionals, loops, or nested functions in order to ensure that Hooks are called in the same order each time a component renders. The order is important for how React [associates Hook calls](https://reactjs.org/docs/hooks-faq.html#how-does-react-associate-hook-calls-with-components) with components. So if we conditionally render a Hook, for instance, **the order of the Hooks could change between renders of a component**, completely messing up the Hooks system.

Sometimes, though, despite the rules, we do want to conditionally call a React Hook, especially when we don't have access to the implementation of a custom Hook. Let's learn how to be rule breakers. 😎

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/conditional-react-hooks</link>
            <guid isPermaLink="false">conditional-react-hooks</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[hooks]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 27 Dec 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Quick way to sort a JavaScript array by multiple fields]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/quick-way-sort-javascript-array-multiple-fields</link>
            <guid isPermaLink="false">quick-way-sort-javascript-array-multiple-fields</guid>
            <category><![CDATA[arrays]]></category>
            <category><![CDATA[typescript]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 20 Dec 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[10 modern JavaScript features to be awesome at React]]></title>
            <description><![CDATA[
One of my favorite sayings about React is that it's "Just JavaScript™." For better or worse, React hitched its ride with JavaScript. It's "for better" because as JavaScript improves, React also gets better (and maybe easier too?). However, it's "for worse" because it means that we really need to be good at JavaScript in order to be good at React. And that can be a barrier to entry.

I used to tell folks that before they even started learning React, they should be really solid in JavaScript. **My thinking was that the more comfortable they were with JavaScript, the easier React would be for them.** I had the best of intentions, but it was still gate-keeping. My bad. 😔

Now I just tell people to learn however they learn best. It's totally fine to start learning React with basic JavaScript skills. Lots of people get the energy and desire to keep learning by building things. However, **I still feel that in order to take our React skills to the next level, we will need a solid grasp of modern JavaScript.**

I want to highlight 10 features of "modern JavaScript" that I believe go hand-in-hand with React. So whether you're considering learning React, and you want to get a handle of modern JavaScript first, or you've already been developing in React and want to fully understand all the JavaScript features you see surrounding React, these are for you. For the features you don't know well yet, feel free to follow the links to learn more.

## 1. ECMAScript Modules (i.e. `import`/`export`)

I see a lot of confusion around imports and when to use named imports versus default imports. Well, the import style depends on how it was exported. There are two kinds of exports: named exports (one or more per file) and default exports (only one per file).

```js
// Example.js

export function calculateRatio(x, y) {
  // used in `Example`
}

export function Helper(props) {
  // used in `Example`
}

export default function Example(props) {
  // Renders `<Helper />`
  // Uses `calculateRatio`
}
```

Generally, you'll either have a file with 1 or more named exports (typically helper functions) or a file with a single default export (typically a React component). But it's certainly possible to combine them.

Similarly, there are also two types of imports: named imports and default imports.

```js
import Example, { Helper, calculateRatio } from './Example'
```

**In short, named imports go within the curly braces and the single default import is outside of them.** How your React codebase is organized will determine how you will need to import within files.

There are more features with `import`/`export` like re-exporting, import renaming, importing as an object, side-effect module loading, and more. Read [ECMAScript 6 modules: the final syntax](https://2ality.com/2014/09/es6-modules-final.html) for more details.

## 2. Arrow functions

Arrow functions are a shorthand syntax for defining functions in JavaScript. Like with everything in JavaScript there are different opinions on how often arrow functions should be used because of their terseness. **Some folks (like myself) replace all functions with arrow functions, while others only use it in certain cases.**

```js
const VALUES = [1, 6, 3, 9, 12, 42, 33]

// OG function
const sums = VALUES.map(function (value) {
  return value + value
})

// arrow function w/ return
const sums = VALUES.map((value) => {
  return value + value
})

// arrow function w/ implicit return
const sums = VALUES.map((value) => value + value)
```

As you can see, the arrow function really wins with saving on characters, but for those unfamiliar with the syntax it really loses with clarity.

Arrow functions can exist everywhere within your React app:

```jsx
// as a component definition (w/ implicit return)
const Example = (props) => (
  <List items={VALUES}>
    {/* as a render prop (w/ implicit return) */}
    {(item) => (
      {/* as an event callback */}
      <button onClick={() => {
        logEvent(item)
      }}>
        {item}
      </button>
    )}
  </List>
)
```

If you want to know more interesting details about arrow functions, including how they don't support `this`, read through my [detailed post on arrow functions](/blog/learning-es6-arrow-functions/).

## 3. String interpolation

We no longer need to do string concatenation. Using string literals, we can now do string interpolation in JavaScript.

```js
const firstName = 'Ben'
const lastName = 'Ilegbodu'

// the values within `firstName` and `lastName`
// are substituted into where the tokens are
// output: Name: Ilegbodu, Ben
console.log(`Name: ${lastName}, ${firstName}`)

// before
console.log('Name: ' + lastName + ', ' + firstName)
```

**Pretty much anywhere where you used to use string concatenation, you can replace with string interpolation using string literals (the back-ticks).** And the `${}` syntax isn't _just_ variable interpolation; it's _expression_ interpolation. Anything expression can go inside.

To learn more, you can deep dive into [Template literals & tagged templates](/blog/learning-es6-template-literals-tagged-templates/). Oh, and template literals also support [nested string interpolation](/blog/nested-string-interpolation-in-javascript/) as well.

## 4. Enhanced object literals

JavaScript object literals support a shorthand when the name of the key matches the existing variable name:

```js
const getCar = (make, model, age, price) => {
  const value = price - age * 1000

  return {
    make,
    model,
    age,
    value,
  }

  // before
  // return {
  //   make: make,
  //   model: model,
  //   age: age,
  //   value: value,
  // }
}
```

Javascript object literals also support computed property keys:

```js
const value = 'hello'
const object = {
  name: 'Ben',
  location: 'Bay Area',
  [value]: 'bye',
}

console.log(object)
// expected output:
// {
//   name: "Ben",
//   location: "Bay Area",
//   hello: "bye"
// }
```

These come in handy pretty much anywhere you're constructing objects. **I try to name my variables or my function arguments such that I can leverage object literal shorthand.** Read more about [Enhanced object literals](/blog/learning-es6-enhanced-object-literals/).

## 5. Array destructuring

Array destructuring makes it possible to easily pluck out ordered values in arrays and create variables. It's used a lot with React hooks because of the [`useState` hook](https://reactjs.org/docs/hooks-state.html):

```js
const Example = () => {
  // `useState` returns a 2-element array
  // declare `count` and assign it first element
  // declare `setCount` and assign it second element
  const [count, setCount] = useState(0)

  // ...
}
```

**Array destructuring is positional, so the names of the variables can be anything I want them to be.**

Another fun use case for array destructuring is with [`Object.entries`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries):

```js
const person = {
  name: 'Ben Ilegbodu',
  title: 'Principal Frontend Engineer',
  location: 'Bay Area',
}

Object.entries(([key, value]) => {
  console.log(`${key}: ${value}`)
})

// expected output:
// "name: Ben Ilegbodu"
// "title: Principal Frontend Engineer
// "location: Bay Area"
```

I often chain `Object.entries` with [`.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) or [`.reduce`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce) when performing data transformations in helper utilities.

For more details, check out [React Hooks: Array Destructuring Fundamentals](https://kentcdodds.com/blog/react-hooks-array-destructuring-fundamentals) or my [deep dive into destructuring](/blog/learning-es6-destructuring/).

## 6. Object destructuring

Object destructuring is like array destructuring but for objects. 😎

```js
const { lName, fName } = { fName: 'John', age: 15, lName: 'Doe' }

// output: Doe, John
console.log(`${lName}, ${fName}`)
```

Object destructuring comes in super handy with plucking properties from component props:

```js
const Input = (props) => {
  const { value, id, onChange } = props

  // `value` === `props.value`
  // `id` === `props.id`
  // `onChange` === `props.onChange`
}
```

And what's even better, we can use object destructuring in the function arguments:

```js
const Input = ({ value, id, onChange }) => {
  // `props` argument never exists
}
```

Many times we have components that take unknown props that we will ultimately pass along. We can use rest operator (`...`) for this:

```js
const Input = ({ value, id, onChange, ...otherProps }) => {
  // `otherProps` is an object with all the other props
  // besides `value`, `id` & `onChange`
}
```

With object destructuring, we can also change the name of the variable created and even use computed keys. For more on object destructuring, take a look at my [Destructuring](/blog/learning-es6-destructuring/) post. For more on destructured parameters, you can read my [Parameter handling](/blog/learning-es6-parameter-handling/) post.

## 7. Spread operator

The [spread operator (`...`)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) usually goes hand-in-hand with the rest operator. It looks identical to the rest operator excepts its used in array and object literals.

```js
const addItem = (list, item) => {
  // add item to the beginning of the
  // list returning a new array instead
  // of modifying the existing one
  return [item, ...list]
}

const addName = (info, name) => {
  // create a copy of the object, add
  // the name key, and return the new object
  return {
    ...info,
    name,
  }
}
```

**The goal with the spread operator is to never mutate data**, but make a copy first and add to the copy. JSX also supports the [spread attributes](https://reactjs.org/docs/jsx-in-depth.html#spread-attributes):

```jsx
const Input = ({ value, id, onChange, ...otherProps }) => {
  // ...

  return (
    <input
      type="text"
      id={id}
      value={value}
      onChange={onChange}
      {...otherProps}
    />
  )
}
```

## 8. Optional chaining

The [optional chaining operator (`?.`)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining) allows us to access properties deeply nested within an object without having to verify that each property level exists:

```js
const processUser = (user) => {
  const userStreet = user?.address?.street

  // if `user` or `address` undefined/null,
  // then `userStreet` will be undefined.
  // otherwise `userStreet` will have the value
}
```

**Bonus:** optional chaining can also be combined with the [nullish coalescing operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator) to safely default a missing value.

```js
const processUser = (user) => {
  const userStreet = user?.address?.street ?? 'Unknown'

  // if `user` or `address` undefined/null,
  // then `userStreet` will be "Unknown"
  // otherwise `userStreet` will have the value
}
```

## 9. Promises & Fetch API

The [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) is a utility for asynchronously making network requests. It returns a [`Promise`](https://developer.mozilla.org/en-US/docs/Web/API/Promise) that will resolve with a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) object:

```js
window.fetch('https://api.benmvp.com/')
  .then((res) => res.json())
  .then((data) => {
    console.log(data)

    // ...
  })
  .catch((err) => {
    console.error(err)
  }
```

Many asynchronous utilities, like `window.fetch`, now use promises instead of callbacks. Promises can be passed around like objects, auto-settled, composed, and a slew of other tings. Check out my [Promises](/blog/learning-es6-promises/) post for all of the details.

## 10. Async functions

An [async function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) is a function that is declared with the `async` keyword. It uses the `await` keyword to enable asynchronous, promise-based behavior to be written in a synchronous style, avoiding the promise chains.

```js
const request = async () => {
  try {
    const res = await window.fetch('https://api.benmvp.com/')
    const data = await res.json()

    // ...
  } catch (err) {
    console.error(err)
  }
}
```

If you no longer have to support Internet Explorer you should be able to use async functions native in the browser! 🎉

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/10-modern-javascript-features-awesome-react</link>
            <guid isPermaLink="false">10-modern-javascript-features-awesome-react</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[ecmascript]]></category>
            <category><![CDATA[proposals]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 13 Dec 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Quickie fetch JSON helper for TypeScript]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/quickie-fetch-json-helper-for-typescript</link>
            <guid isPermaLink="false">quickie-fetch-json-helper-for-typescript</guid>
            <category><![CDATA[fetch]]></category>
            <category><![CDATA[type-assertion]]></category>
            <category><![CDATA[fetch-api]]></category>
            <category><![CDATA[json]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 06 Dec 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Filtering undefined elements from an array in TypeScript]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/filtering-undefined-elements-from-array-typescript</link>
            <guid isPermaLink="false">filtering-undefined-elements-from-array-typescript</guid>
            <category><![CDATA[arrays]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 29 Nov 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Type-checking React useReducer in TypeScript]]></title>
            <description><![CDATA[
The biggest benefit I've found with TypeScript is type-checking functions. TypeScript ensures that I pass the correct types to a helper function and it provides the type of the return value for me to use. Similarly, when writing functions I can be assured that I'm receiving the correct types as arguments and that I return the type that I intend.

In React, this manifests itself in several ways. The main way is [type-checking props](/blog/react-prop-types-with-typescript/). After all, **React components are just special functions with input (props) and output (markup)**. And we can do all kids of sophisticated things leveraging TypeScript's ability to type-check functions, like setting up [conditional React props](/blog/conditional-react-props-typescript/), creating [polymorphic React components](/blog/polymorphic-react-components-typescript/), and defining [generic React components](/blog/generic-react-components-typescript/).

React also has [hooks](https://reactjs.org/docs/hooks-intro.html) which are special types of functions that let us use state and other React features using function components. In general, **there's nothing really special needed to type hooks**. For instance, we can let [type inference](https://www.typescriptlang.org/docs/handbook/type-inference.html) do all the work with [`useState`](https://reactjs.org/docs/hooks-state.html):

```typescript
import React, { useState } from 'react'

const Example = () => {
  // with type inference TypeScript knows that
  // `count` is a number` & `setCount` takes a number
  // based on `0` being passed as an initial value
  const [count, setCount] = useState(0)

  return (
    <div>
      <p>You clicked {count} times!</p>
      <button onClick={() => setCount((curCount) => count + 1)}>
        Click me
      </button>
    </div>
  )
}
```

Because of how `useState` is typed (it's a [generic function](https://www.typescriptlang.org/docs/handbook/generics.html)), `count` is inferred to be a `number` and `setCount` is inferred to be a function that is passed a `number`. This is all because of the initial value `0` (a number) that was passed to `useState`.

However, **[`useReducer`](https://reactjs.org/docs/hooks-reference.html#usereducer) _is_ one hook that requires additional type hand-holding**. The docs suggest using `useReducer` over `useState` when we "have complex state logic that involves multiple sub-values." But to try to keep things as simple as possible, let's take the traditional [Redux todos example](https://github.com/reduxjs/redux/tree/176e66adc9a90df2690620075e82dca21cc1cd25/examples/todos) and convert it to `useReducer` + Typescript:

```typescript
type Visibility = 'all' | 'completed' | 'active'
interface State {
  todos: {
    id: number
    text: string
    completed: boolean
  }[]
  visibility: Visibility
}
type Action =
  | { type: 'add_todo'; id: number; text: string }
  | { type: 'toggle_todo'; id: number }
  | { type: 'set_visibility'; visibility: Visibility }

const reducer = (state: State, action: Action): State => {
  switch (action.type) {
    case 'add_todo':
      return {
        ...state,
        todos: [
          ...state.todos,
          { id: action.id, text: action.text, completed: false },
        ],
      }
    case 'toggle_todo':
      return {
        ...state,
        todos: state.todos.map((todo) =>
          todo.id === action.id
            ? { ...todo, completed: !todo.completed }
            : todo,
        ),
      }
    case 'set_visibility':
      return {
        ...state,
        visibility: action.visibility,
      }
  }
}

let nextTodoId = 0
const Example = () => {
  const [state, dispatch] = useReducer(reducer, {
    todos: [],
    visibility: 'all',
  })

  return (
    <main>
      <h1>Todos!</h1>

      <TodoForm
        onSubmit={(text) => {
          dispatch({ type: 'add_todo', text, id: nextTodoId++ })
        }}
      />

      <TodosList
        todos={state.todos}
        filter={state.visibility}
        onToggleCompleted={(id) => {
          dispatch({ type: 'toggle_todo', id })
        }}
      />

      <RadioGroup
        value={state.visibility}
        onChange={(newVisibility) =>
          dispatch({ type: 'set_visibility', visibility: newVisibility })
        }
      >
        <Radio value="all">All</Radio>
        <Radio value="completed">Completed</Radio>
        <Radio value="active">Active</Radio>
      </RadioGroup>
    </main>
  )
}
```

Ok, I know that may look like a lot. But it's actually only the top portion that is the TypeScript addition. The majority of the code is the implementation which leverages type inference to ensure type safety.

Let's break thing down bit by bit.

```typescript
type Visibility = 'all' | 'completed' | 'active'
interface State {
  todos: {
    id: number
    text: string
    completed: boolean
  }[]
  visibility: Visibility
}
```

First we define the shape of our state. Just like with props, **we can't get away with hand-waving the state shape or defining it implicitly in code**. It has to be explicitly defined. In this case, our state has two required properties: `todos` (an array of todo objects with their own required properties) and `visibility` (an "enum" of visibility states).

```typescript
type Action =
  | { type: 'add_todo'; id: number; text: string }
  | { type: 'toggle_todo'; id: number }
  | { type: 'set_visibility'; visibility: Visibility }
```

Next, using a [discriminated union](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#discriminated-unions), we define the valid actions. **This discriminated union is what becomes the linchpin and provides the strong typing for `useReducer`**.

It means that an action can _only_ have one of these 3 shapes. The fact that we cannot have a `type` other than the 3 listed catches any typos and prevents the need for having shared constants. An `'add_todo'` action _must_ have both `id` & `text` properties, whereas a `'toggle_todo'` cannot have a `text` property. The `visibility` property for `'set_visibility'` must be one of the 3 `Visibility` options (which also matches the `visibility` state property).

```typescript
const reducer = (state: State, action: Action): State => {
  switch (action.type) {
    case 'add_todo':
      return {
        ...state,
        todos: [
          ...state.todos,
          { id: action.id, text: action.text, completed: false },
        ],
      }
    case 'toggle_todo':
    // ...
    case 'set_visibility':
    // ...
  }
}
```

The `reducer` function is specifically typed to take `State` and `Action` arguments, and return a `State` object. **This function definition provides enough type information that the rest of the reducer can be strongly typed just using type inference**.

When we use the `switch` on `action.type`, we can _only_ have `case` statements for `'add_todo'`, `'toggle_todo'` and `'set_visibility'`. Any other `case` values will be an error. Furthermore, if we leave off one of the actions from the `switch`, TypeScript will know that there's a chance that the function can return `undefined`. And because we say the reducer must return `State`, TypeScript will complain thanks to [union exhaustiveness checking](https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#union-exhaustiveness-checking).

Within a given `case` statement, TypeScript now knows which action we are in. Therefore trying to access `action.visibility` within `'add_todo'`, `action.text` within `'toggle_todo'` or `action.id` within `'set_visibility'` will all be errors. Once again this is all thanks to the `Action` being a discriminated union.

Last, but not least, the return values must be valid `State` objects. So if I forget to `...state`, I will be missing properties of `State` and TypeScript will complain.

All pretty sweet, huh? 🤯

```typescript
// highlight-range{3-6,13}
let nextTodoId = 0
const Example = () => {
  const [state, dispatch] = useReducer(reducer, {
    todos: [],
    visibility: 'all',
  })

  return (
    <main>
      <h1>Todos!</h1>
      <TodoForm
        onSubmit={(text) => {
          dispatch({ type: 'add_todo', text, id: nextTodoId++ })
        }}
      />
      ...
    </main>
  )
}
```

Now, down in the component itself, `useReducer` (also a generic function by the way) is able to infer types based on the type of the `reducer` function. So it knows `state` is `State` and that `dispatch` is a function that can only dispatch `Action` objects. In addition, TypeScript ensures that the initial state (the second parameter of `useReducer`) is a full `State` object.

Finally, when we call `dispatch`, it must be a valid `Action` object. There's no need to use a constant for the `'add_todo'` type because it must match one of the valid `Action` types. If we were to change the name of the type to just `'add'`, we would get TypeScript errors.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/type-checking-react-usereducer-typescript</link>
            <guid isPermaLink="false">type-checking-react-usereducer-typescript</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[hooks]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 22 Nov 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Generic React Components in TypeScript]]></title>
            <description><![CDATA[
Two weeks ago I wrote about [Conditional React prop types with TypeScript](/blog/conditional-react-props-typescript/). Last week we learned about [Polymorphic React components in TypeScript](/blog/polymorphic-react-components-typescript/). And today we're continuing the React + TypeScript theme, this time focusing on creating generic React components using TypeScript.

To better explain what we're trying to do, let's use a somewhat real-world example. Let's say we have a `<List />` component that we pass an array of items and it exposes a [render prop](https://ui.dev/react-render-props/) to allow the caller to decide how to render a given item. We could use it to render the full list of active players in the NBA:

```js
const NBAPlayers = () => {
  // 👋🏾 hand-wavy custom hook that returns an array of players
  const players = usePlayers('nba')

  return (
    <List items={players} dir="horizontal" dividers windowing>
      {(player) => (
        <section>
          <img src={player.thumbUrl} alt={player.name} />
          <h1>{player.name}</h1>
          <p>{player.shortBio}</p>
        </section>
      )}
    </List>
  )
}
```

Now `<List />` **takes care of all the UI things other than rendering a given item**. Things like handling the layout of the items (direction, spacing, etc.), including dividers in between the items, alternating background colors, and more. It could even support advanced functionality like _windowing_ for large lists in order to optimize the creation of DOM nodes by only rendering those that are visible in the viewport (a la [`react-window`](https://github.com/bvaughn/react-window)).

What makes `<List />` _generic_ is that it doesn't just supporting rendering NBA players. It can render lists of _any_ data. So instead of using it render NBA players, we can use it to render JavaScript frameworks:

```js
const JSFrameworks = () => {
  // 👋🏾 hand-wavy custom hook that returns an array of JS frameworks
  const frameworks = useFrameworks('js')

  return (
    <List items={frameworks} dir="vertical">
      {(framework) => (
        <dl>
          <dt>Name</dt>
          <dd>{framework.name}</dd>

          <dt>Created</dt>
          <dd>{framework.since}</dd>

          <dt>Author</dt>
          <dd>{framework.author}</dd>
        </dl>
      )}
    </List>
  )
}
```

Which list do you think is longer: the list of NBA players or the list of JavaScript frameworks? 😂

So `<List />` works much like [`Array.prototype.map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map). It accepts an array of items, calls a function for each item (i.e. the render prop), and then passes the item to that function. **The type of the items themselves does not matter.** The `<List />` component is flexible. The first call to `<List />` had an array of players and the second, an array of JavaScript frameworks.

A streamlined JavaScript implementation may look something like:

```js
const List = ({ children, dir, dividers, items, windowing }) => {
  const className = genClassName({ dir, dividers })
  const visibleItems = useWindowing(items)

  return (
    <div className={className}>
      {visibleItems.map((item) => (
        <div key={item.id} className="item">
          {children(item)}
        </div>
      ))}
    </div>
  )
}
```

Trust me. This is _very streamlined_. If only it were this simple. 😅 But there are two things I want to point out.

First, the type of the argument passed to the `children` render prop matches the type of the elements in the array. It's a sort of indirect association between the `items` and `children` props. When we use TypeScript, we will want the types to match so that the caller of the `<List />` will receive the correct type when defining the render prop. **We don't want the caller to have to perform a [type assertion](https://www.typescriptlang.org/docs/handbook/basic-types.html#type-assertions).**

Second, we are requiring the `item` to be an object with an `id` property so we can use it as the `key` prop (because using the [array index as the key is an anti-pattern](https://reactjs.org/docs/lists-and-keys.html#keys)). When we use TypeScript, we will **need to enforce that the array contains objects that have an `id` property.**

Now let's look at how we can re-implement the `List` component in TypeScript to satisfy both of these needs. The final result looks like:

```typescript
interface Props<T> {
  children: (item: T) => React.ReactNode
  dir: 'horizontal' | 'vertical'
  dividers?: boolean
  items: T[]
  windowing?: boolean
}

interface IdObj {
  id: string | number
}

const List = <T extends IdObj>({
  children,
  dir,
  dividers,
  items,
  windowing,
}: Props<T>) => {
  const className = genClassName({ dir, dividers })
  const visibleItems = useWindowing(items, windowing)

  return (
    <div className={className}>
      {visibleItems.map((item) => (
        <div key={item.id} className="item">
          {children(item)}
        </div>
      ))}
    </div>
  )
}
```

The solution makes use of [TypeScript generics](https://www.typescriptlang.org/docs/handbook/generics.html) and [generic constraints](https://www.typescriptlang.org/docs/handbook/generics.html#generic-constraints). So if you're looking to strengthen your TypeScript generics muscles, I suggest checking out [_TypeScript Generics for People Who Gave Up on Understanding Generics_](https://ts.chibicode.com/generics) by [Shu Uesugi](https://twitter.com/chibicode). Now let's break down the solution.

```typescript
// highlight-range{1,2,5}
interface Props<T> {
  children: (item: T) => React.ReactNode
  dir: 'horizontal' | 'vertical'
  dividers?: boolean
  items: T[]
  windowing?: boolean
}
```

Here we have our typical `interface` definition for the types of our props, except it's genericized using `Props<T>`. The `T` can be any identifier, but sadly **the common convention is a single character, usually `T`**.

With our generic type in hand, we now declare that the type of `items` is an array of `T` types (`T[]`). We don't know what `T` will be, but it has to be an array of them. And then we make the association with the `children` render prop by defining its type as `(item: T) => React.ReactNode`. So it will be passed a single `T` item and then of course return markup. We've now met our first need of connecting the types of `items` & `children` together. 👍🏾

```typescript
interface IdObj {
  id: string | number
}
```

This `IdObj` interface is the base of solving the second need: that the `items` are an object with at least an `id` property. The type of the (required) `id` property is `string | number` because that is the type of the `key` prop on React elements and components. But `IdObj` is just part of the puzzle.

```typescript
// highlight-range{1,7}
const List = <T extends IdObj>({
  children,
  dir,
  dividers,
  items,
  windowing,
}: Props<T>) => {
  // ...
}
```

The `<T extends IdObj>` is called [generic constraining](https://www.typescriptlang.org/docs/handbook/generics.html#generic-constraints). So `T` can't just be _anything_. And because `IdObj` defines an object with a required `id` property, by declaring that `T` must extend `IdObj`, we are **constraining `T` to also be an object with a required `id` property**. It can have more properties than `id` of course, but that's the absolute minimum. Second need completed. 👍🏾👍🏾

```typescript {4}
return (
  <div className={className}>
    {visibleItems.map((item) => (
      <div key={item.id} className="item">
        {children(item)}
      </div>
    ))}
  </div>
)
```

And really, `List` doesn't care about anything else other than that minimum because that's all it requires for its code (in order to set the `key` prop). Everything else is offloaded to the caller via the `children` render prop that we described earlier.

Setting up these generic props isn't terribly complex or complicated, but it does take a solid understanding of TypeScript generics which is definitely advanced TypeScript. But the result is a much better developer experience.

```typescript
const JSFrameworks = () => {
  // 👋🏾 hand-wavy custom hook that returns an array of JS frameworks
  const frameworks = useFrameworks('js')

  return (
    <List items={frameworks} dir="vertical">
      {(framework) => (
        <dl>
          <dt>Name</dt>
          <dd>{framework.name}</dd>

          <dt>Created</dt>
          <dd>{framework.since}</dd>

          <dt>Author</dt>
          <dd>{framework.author}</dd>
        </dl>
      )}
    </List>
  )
}
```

As we mentioned earlier, the caller doesn't have to use a type assertion in the render prop to coerce the `framework` argument to the correct type. It's automatically kept in sync with the type of the `frameworks` array passed to the `items` prop. In fact, the TypeScript implementation of the `JSFrameworks` component looks identical to the previous JavaScript version, because **we never have to explicitly define the type of `items` or `children`.** The types are all inferred.

Also, if the type of the array passed to `items` _doesn't_ have the required `id` property, the caller will get the following error:

```text
Type 'Framework[]' is not assignable to type 'IdObj[]'.
  Property 'id' is missing in type 'Framework' but required in type 'IdObj'.
```

We are taking the agreement we made with `List` in JavaScript and enforcing it with TypeScript. 💪🏾

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/generic-react-components-typescript</link>
            <guid isPermaLink="false">generic-react-components-typescript</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[generics]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 15 Nov 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Polymorphic React Components in TypeScript]]></title>
            <description><![CDATA[
Last week I wrote a post about [conditional React prop types with TypeScript](/blog/conditional-react-props-typescript/) that generated a lot of [discussion on Twitter](https://twitter.com/benmvp/status/1323415760220299264). So I wanna continue the theme of how TypeScript levels up React, this time talking about creating _polymorphic components_ with TypeScript.

It's quite possible that you've never heard of a polymorphic component before. It's a pattern for code reuse that's not nearly as popular as [higher-order components](https://ui.dev/react-higher-order-components/), [render props](https://ui.dev/react-render-props/), or, of course, [custom hooks](https://reactjs.org/docs/hooks-custom.html). But it's probably the simplest one.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/polymorphic-react-components-typescript</link>
            <guid isPermaLink="false">polymorphic-react-components-typescript</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[components]]></category>
            <category><![CDATA[design-system]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 08 Nov 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Conditional React props with TypeScript]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/conditional-react-props-typescript</link>
            <guid isPermaLink="false">conditional-react-props-typescript</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[props]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 01 Nov 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Easily kill a process running on a port]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/kill-process-running-port</link>
            <guid isPermaLink="false">kill-process-running-port</guid>
            <category><![CDATA[bash]]></category>
            <category><![CDATA[command-line]]></category>
            <category><![CDATA[npx]]></category>
            <category><![CDATA[til]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 18 Oct 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Helper functions in the React useEffect hook]]></title>
            <description><![CDATA[
The [`useEffect` hook](https://reactjs.org/docs/hooks-reference.html#useeffect) in React by default runs on every re-render:

```js {4-6}
const Example = () => {
  const [count, setCount] = useState(0)

  useEffect(() => {
    document.title = `You clicked ${count} times`
  })

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  )
}
```

You pretty much never want this functionality because the “effect” will happen way more times than it needs to. So as an optimization, `useEffect` takes a second parameter, a “dependencies” array, that will only re-run the effect when the values within the array change across re-renders:

```js {6}
const Example = () => {
  const [count, setCount] = useState(0)

  useEffect(() => {
    document.title = `You clicked ${count} times`
  }, [count]) // Only re-run the effect if count changes

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  )
}
```

This generally works great, and I find it more straightforward than its predecessor [`componentDidUpdate`](https://reactjs.org/docs/react-component.html#componentdidupdate) for class-based React components.

However, sometimes you have helper functions that you need to call from within `useEffect`. And in order to have access to props, state or other derived values, these helper functions are defined as inner functions _within_ the component itself.

Take a look at this totally made up example component:

```js {5-9,17,20}
const Example = () => {
  const [count, setCount] = useState(0)
  const [showMessage, setShowMessage] = useState(true)

  const hideMessage = () => {
    if (count < 10) {
      setShowMessage(false)
    }
  }

  useEffect(() => {
    window
      .fetch('https://api.benmvp.com/')
      .then((res) => res.json())
      .then((data) => {
        if (data.success) {
          hideMessage()
        }
      })
  }, [])

  return (
    <div>
      {showMessage && <p>You clicked {count} times</p>}
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  )
}
```

Now if you are using the [`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks) eslint plugin (which I really hope you are), the `react-hooks/exhaustive-deps` rule will tell you that you need to include the `hideMessage` helper function in your dependencies array.

```shell
React Hook useEffect has a missing dependency: 'hideMessage'.
Either include it or remove the dependency array.
eslint(react-hooks/exhaustive-deps)
```

It seems weird to add a function as a dependency, but because of the nature of [closures & lexical scope](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures), it’s important in order to avoid stale variables. But then if you add `hideMessage` to the dependencies list, you’ll get different eslint error:

```shell
The 'hideMessage' function makes the dependencies of useEffect Hook
(at line 5) change on every render. Move it inside the useEffect callback.
Alternatively, wrap the 'hideMessage' definition into its own useCallback() Hook.
eslint(react-hooks/exhaustive-deps)
```

This time instead of the error being on the `useEffect` dependencies list, it’s about the `hideMessage` helper function itself. Because it’s being declared within the React component function, there’s going to be a new version of it every time the component re-renders. **So adding it to the dependencies list is basically pointless because it’ll cause the dependencies list to be different every re-render.** This is because the previous function will not be the same reference as the next one. You’re undoing the benefit you’re trying to achieve. Although this is super frustrating, it’s pretty cool that the eslint rule is able to help you out this much.

The error provides two suggested options, but I've found that many developers are not quite sure which option is best for their situation. So they'll do _anything_ to get the error to go away. I've even seen them go nuclear and turn off the `react-hooks/exhaustive-deps` rule altogether, which is probably the worst option. By disabling it, they now allow bugs to creep into their other uses of `useEffect` when they forget to add non-function dependencies.

So I wanted to provide a couple of options to solve this problem of helper functions within the `useEffect` hook **without having to disable the `react-hooks/exhaustive-deps` rule**. And also explain in which situation(s) the option would work best.

## Option 1 - Don’t use a helper function

Seems simple enough right? 😄 Helper functions are great abstractions because they provide a helpful name around lines of code. But if your helper is only a few lines of code, you can get rid of the function and move the code within the `useEffect` call.

By the way, if the code was making use of any variables, you will need to add those to the dependencies list.

```js {11-13,16}
const Example = () => {
  const [count, setCount] = useState(0)
  const [showMessage, setShowMessage] = useState(true)

  useEffect(() => {
    window
      .fetch('https://api.benmvp.com/')
      .then((res) => res.json())
      .then((data) => {
        if (data.success) {
          if (count < 10) {
            setShowMessage(false)
          }
        }
      })
  }, [count])

  return (
    <div>
      {showMessage && <p>You clicked {count} times</p>}
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  )
}
```

This option really only works if the function was small. But it's a pretty simple fix!

## Option 2 - Move the helper function within `useEffect`

This is the first suggestion in that second error we got. It may seem a bit weird, but if you move the helper function within the `useEffect` hook, **it’s no longer being redeclared with every component re-render.** Instead, it’s only being redeclared every time the effect is re-run. And since the helper function is now _inside_ the `useEffect` hook, it no longer needs to be listed in the dependencies. However, any variables that the function used from outside of the `useEffect` will need to be added to the dependencies list.

```js {6-10,17,20}
const Example = () => {
  const [count, setCount] = useState(0)
  const [showMessage, setShowMessage] = useState(true)

  useEffect(() => {
    const hideMessage = () => {
      if (count < 10) {
        setShowMessage(false)
      }
    }

    window
      .fetch('https://api.benmvp.com/')
      .then((res) => res.json())
      .then((data) => {
        if (data.success) {
          hideMessage()
        }
      })
  }, [count])

  return (
    <div>
      {showMessage && <p>You clicked {count} times</p>}
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  )
}
```

This option is only feasible if the helper function is only called from within the `useEffect` hook. If it’s called elsewhere in the component, or even in another `useEffect` hook, it will not be accessible in those places.

## Option 3 - Move the helper outside of the function component

The problem we’re having with this `hideMessage` helper function is that it’s being redeclared with every component re-render. By moving the helper function outside of the function component, either within the file or in a separate file, the helper will only have the one definition. **It will not change across component re-renders.**

As a result, you don’t even need to include the function in the dependencies list. This is why the eslint rule doesn’t complain about other imported functions that you call from within `useEffect`.

However, any props, state or other derived values that the function needs will now need to be passed in as function arguments and will also need to be dependencies of `useEffect`.

```js {1-5,17,20}
const hideMessage = (count, setShowMessage) => {
  if (count < 10) {
    setShowMessage(false)
  }
}

const Example = () => {
  const [count, setCount] = useState(0)
  const [showMessage, setShowMessage] = useState(true)

  useEffect(() => {
    window
      .fetch('https://api.benmvp.com/')
      .then((res) => res.json())
      .then((data) => {
        if (data.success) {
          hideMessage(count, setShowMessage)
        }
      })
  }, [count])

  return (
    <div>
      {showMessage && <p>You clicked {count} times</p>}
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  )
}
```

This option works well if the helper isn’t relying on lots of variables because then all of them would have to be passed as function arguments. This option can feel a bit clunky if the function needs to call a state setter (aka `setShowMessage`) instead of returning a value.

## Option 4 - Use the `useCallback` hook

This is the other suggestion in the lint error we got. The [`useCallback` hook](https://reactjs.org/docs/hooks-reference.html#usecallback) returns a “memoized” callback. It basically returns a cached version of the function based on the value of the parameters. If the parameters stay the same, **you’ll get back the exact same function reference every time**.

`useCallback` helps us get around the problem of the helper function being redeclared with every re-render because now we’ll get back the same function reference. It will only change if and when its parameters change.

```js {5-9,17,20}
const Example = () => {
  const [count, setCount] = useState(0)
  const [showMessage, setShowMessage] = useState(true)

  const hideMessage = useCallback(() => {
    if (count < 10) {
      setShowMessage(false)
    }
  }, [count])

  useEffect(() => {
    window
      .fetch('https://api.benmvp.com/')
      .then((res) => res.json())
      .then((data) => {
        if (data.success) {
          hideMessage()
        }
      })
  }, [hideMessage])

  return (
    <div>
      {showMessage && <p>You clicked {count} times</p>}
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  )
}
```

Now when we add `hideMessage` in the dependencies list of `useEffect`, we no longer get an error because `hideMessage` is memoized. Our call to `useCallback` also has a dependencies list, which contains the variables being used in the function. It's similar to how `useEffect` works. And that same `react-hooks/exhaustive-deps` eslint rule will show an error if you forget dependencies in `useCallback` as well.

**This option will work in every situation and probably requires the least code change.** You wrap it in `useCallback` and call it a day. But it’s actually my least favorite option for 2 reasons.

The first is that `useCallback` is a lesser-known hook so when others see it, it causes an extra cognitive load for them to understand what’s going on. Memoization is not a well-known concept.

The second reason is that it requires React to do more work. **Although it looks easy, memoization isn’t free.** There’s a lot of code that React executes to make it all work. The previous 3 options, on the other hand, solve the problem with regular ol’ JavaScript. In theory, less work means better performance.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/helper-functions-react-useeffect-hook</link>
            <guid isPermaLink="false">helper-functions-react-useeffect-hook</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[hooks]]></category>
            <category><![CDATA[useEffect]]></category>
            <category><![CDATA[memoization]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 11 Oct 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Four characters can optimize your React component]]></title>
            <description><![CDATA[
So… yeah the title is kinda clickbait-y, but it’s kinda true. Take a look at these two code snippets.

First:

```js
// Example 1

const Counter = () => {
  const [count, setCount] = useState(
    Number.parseInt(window.localStorage.getItem(cacheKey)),
  )

  useEffect(() => {
    window.localStorage.setItem(cacheKey, count)
  }, [cacheKey, count])

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount((prevCount) => prevCount - 1)}>-</button>
      <button onClick={() => setCount((prevCount) => prevCount + 1)}>+</button>
    </div>
  )
}
```

Second:

```js
// Example 2

const Counter = () => {
  const [count, setCount] = useState(() =>
    Number.parseInt(window.localStorage.getItem(cacheKey)),
  )

  useEffect(() => {
    window.localStorage.setItem(cacheKey, count)
  }, [cacheKey, count])

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount((prevCount) => prevCount - 1)}>-</button>
      <button onClick={() => setCount((prevCount) => prevCount + 1)}>+</button>
    </div>
  )
}
```

Can you spot the difference? Yes? Good eye! 🔬 If not, I’ll give you a hint and zero in on the `useState` calls.

First:

```js
// Example 1

const [count, setCount] = useState(
  Number.parseInt(window.localStorage.getItem(cacheKey)),
)
```

Second:

```js
// Example 2

const [count, setCount] = useState(() =>
  Number.parseInt(window.localStorage.getItem(cacheKey)),
)
```

How about now? 😄 They look almost the same right? Ok, I won't keep you in suspense (pun intended). 😂

The difference is the code for the initialization of the state. The first example retrieves the value from `localStorage`, parses it into an integer, and then sets it as the initial value for the `count` state.

```js
// Example 1

const [count, setCount] = useState(
  Number.parseInt(window.localStorage.getItem(cacheKey)),
)
```

The second example is _almost_ similar, except it **passes a function** that retrieves the value from `localStorage`, parses it into an integer, and **returns** the value.

```js {3}
// Example 2

const [count, setCount] = useState(() =>
  Number.parseInt(window.localStorage.getItem(cacheKey)),
)
```

Because of the terseness of [arrow functions](/blog/learning-es6-arrow-functions/) with an implicit return value, the difference between the first and second examples is only 4 characters (plus some whitespace). And depending on what we’re doing to get the initial value (in our case reading from `localStorage` and parsing the value), adding those 4 characters can improve the performance of your React function component.

Passing a function to `useState` instead of a direct value is called [_lazy initialization_](https://reactjs.org/docs/hooks-reference.html#lazy-initial-state). According to the `useState` docs, you use lazy initialization with `useState` when the calculation of the initial state value is an expensive computation. This is because the lazy initialization function is **only executed the first time when the state is created**. On subsequent re-renders, the function is disregarded.

As a reminder, the way the `useState` hook works is that the first time `Counter` is rendered, it creates the `count` state with its initial value. Then when we call `setCount`, the entire `Counter` function gets called again and `count` has its updated value. And this re-rendering happens every time the `count` state is updated. All the while, that initial value is never used again.

So in the first example, if we’re reading the value from `localStorage` for every re-render, but we only needed its value for the first render, **we’re doing a bunch of unnecessary computation.** The second example using the lazy initialization function prevents that unnecessary computation.

Still a tiny bit confused? Let’s rewrite the first example to hopefully make things a bit clearer. Instead of passing the value from `localStorage` directly to `useState`, let's store it in a variable first and _then_ pass it to `useState` instead.

```js
// Example 1

const Counter = () => {
  const initialValue = Number.parseInt(window.localStorage.getItem(cacheKey))
  const [count, setCount] = useState(initialValue)

  // rest of the component
}
```

Now we can see that every time we re-render and call `Counter` again, we’re retrieving the value from `localStorage` every time, even though it's ultimately only needed the very first time. The second example _does_ always pass the function to `useState` every re-render, but `useState` only calls it the very first time. That’s why it’s called _lazy_ initialization.

And if I fully write out the lazy initialization function, it’s even clearer how different the two examples are:

```js
// Example 2

const Counter = () => {
  const [count, setCount] = useState(function() {
    return Number.parseInt(window.localStorage.getItem(cacheKey)),
  })

  // rest of the component
}
```

Since the lazy initialization function is only called once, should you use it all the time? Even for something like this:

```js
// returning a primitive value

const Counter = () => {
  const [count, setCount] = useState(() => 0)

  // rest of the component
}
```

Or this:

```js
// returning a prop or existing variable

const Counter = ({ initialCount }) => {
  const [count, setCount] = useState(() => initialCount)

  // rest of the component
}
```

In these cases, the initial value is a simple value or an already calculated variable. Even though the function is only being called once, there still is a cost to creating the function every time. And it’s likely that the cost of creating the function would be higher than just passing the value or variable along. This would be an over-optimization.

**So when should you use lazy initialization?** Like almost everything, it depends. 😄 The guideline from the docs is when you’re doing an “expensive computation.” Reading from `localStorage` would be an expensive computation. Using [`.map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map), [`.filter()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), [`.find()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find), etc. on arrays would be expensive computations. A good way to think of it is that if you have to call a function to get the value, it’s likely an expensive enough computation that it warrants using lazy initialization.

I’d likely use it to initialize state to be the current date/time:

```js {2}
const Clock = () => {
  const [time, setTime] = useState(() => new Date())

  useEffect(() => {
    const intervalId = setInterval(() => {
      setTime(new Date())
    }, 1000)

    return () => {
      clearInterval(intervalId)
    }
  }, [tickAmount])

  return <p>The time is {time.toLocaleTimeString()}.</p>
}
```

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/four-characters-optimize-react-component</link>
            <guid isPermaLink="false">four-characters-optimize-react-component</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[hooks]]></category>
            <category><![CDATA[useState]]></category>
            <category><![CDATA[performance]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sat, 03 Oct 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Configurability in a Design System]]></title>
            <description><![CDATA[
A few months ago I wrote a post called [What exactly is a "Design System"?](/blog/what-exactly-is-a-design-system/). And at the very end, I mentioned that I'd share more thoughts on "how to spin up and maintain a React component library." So in this post, I'm beginning that process.

An organization will create a JavaScript component library to be a shared abstraction of components to encapsulate aesthetics and logic. As a result, developers don't have to keep rebuilding these components every time they need them in a different app. The component library is intended to **allow feature/product engineers to focus on the business logic of the app** instead of having to build yet another dialog component.

Once you start building your component library, one of the first questions you will have to decide is how configurable do you want to make your components. A component with very little configuration will be 100% on-brand and will be very easy to use. However, if small tweaks are needed to match the design, that rigid component can cause a lot of friction. Conversely, a component with full flexibility is more likely to adapt to any given design, but not only requires **more effort in building and maintaining the flexibility in the code**, but also more effort into learning _how_ to configure it to match the design.

When thinking about how flexible I should make a component, I try to consider how likely the dev using the component will want to configure a certain area of functionality. Some areas I'm almost certain they'll say "please don't make me think about this." But other areas they'll likely say "I really need to tweak this."

I've come up with 6 areas of functionality, and ordered them from least to most likely to need flexibility. Let's jump in.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/configurability-design-system</link>
            <guid isPermaLink="false">configurability-design-system</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[design-system]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[components]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Thu, 27 Aug 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Mocking window.location methods in Jest & jsdom]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/mocking-window-location-methods-jest-jsdom</link>
            <guid isPermaLink="false">mocking-window-location-methods-jest-jsdom</guid>
            <category><![CDATA[mock]]></category>
            <category><![CDATA[react]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Thu, 06 Aug 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[A quick trick for Jest asynchronous tests]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/quick-trick-jest-asynchronous-tests</link>
            <guid isPermaLink="false">quick-trick-jest-asynchronous-tests</guid>
            <category><![CDATA[async]]></category>
            <category><![CDATA[await]]></category>
            <category><![CDATA[promises]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Wed, 29 Jul 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Asynchronous testing with Enzyme & React in Jest]]></title>
            <description><![CDATA[
Back in April I wrote a blog post about how I would [choose React Testing Library over Enzyme](/blog/react-testing-library-over-enzyme/). It's probably been my most popular post in the last 3 months! At the end the post, I mentioned that there were many other "nuances about [React Testing Library](https://testing-library.com/react) that help prevent you from testing implementation details." I was planning to just leave it at that statement, but recently I ran into one such nuance while working in a codebase that used [Enzyme](https://enzymejs.github.io/enzyme/). And I just **had** to share it.

## The Problem

It has to do with the **complexity around testing asynchronous events** within components using Enzyme. Let's say for example you had a component that had a form. And `onSubmit` of that form you make an API call to `POST` the form data. And when the successful response returns, you add a new item to a list. It could look something like this:

```js
const Adder = () => {
  const [items, setItems] = useState([])

  const handleSubmit = (data) => {
    submitNewItem(data)
      .then((newItem) => {
        setItems((prevItems) => [...prevItems, newItem])
      })
  }

  return (
    <>
      <AddForm onSubmit={handleSubmit} />
      <ul data-testid="adder-items">
        {items.map((item) => (
          // render UI for each item
        ))}
      </ul>
    </>
  )
}
```

When the `<AddForm />` submits, it calls `submitNewItem` which is a helper function wrapping [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) (or [axios](https://github.com/axios/axios) if you prefer). When we receive the `newItem`, we call `setItems()` with a new array that has the `newItem` appended. By the way, since the new value of `items` is computed using its previous value, we need to [pass a function to `setItems`](https://reactjs.org/docs/hooks-reference.html#functional-updates).

So we set up our test like so, but we run into a problem:

```js {23-24}
import { mount } from 'enzyme'
import Adder from './Adder'
import { submitNewItem } from '../utils'

jest.mock('../utils')

test('new item is added to the UI when the form is successfully submitted', () => {
  // Instead of making a real API call, mock the helper to return a
  // resolved promise with the data that would come back from the API
  submitNewItem.mockResolvedValueOnce({ id: 14, title: 'Gucci sneakers' })

  const component = mount(<Adder />)
  const preventDefault = jest.fn()

  component
    .find('[data-testid="addform-form"]')
    .simulate('submit', { preventDefault })

  expect(preventDefault).toHaveBeenCalledTimes(1)

  component.update()

  // THIS DOESN'T WORK!!
  expect(component.find('[data-testid="adder-items"]')).toHaveLength(1)
})
```

We want to test that the `newItem` was successfully added to state by _checking its existence in the UI_, **not** by inspecting the value in the component's state. But this proves difficult because looking at the implementation, it happens asynchronously after `submitNewItem` has resolved its promise. If you debug the test code, you'll see that the assertion above runs **before the API call even resolves**. Even though we've mocked out `submitNewItem` to immediately return a resolved promise, we still don't have anywhere to "attach" to know when the promise has resolved so that we can safely verify the UI.

If you Google around, you'll likely come across [this issue in the Enzyme repo](https://github.com/enzymejs/enzyme/issues/1587) that started nearly 2 years ago. And it's full of crazy workarounds that pretty much all involve testing deep implementation details by reaching into [`component.instance()`](https://enzymejs.github.io/enzyme/docs/api/ReactWrapper/instance.html). But that's not what we want to do!

## The Enzyme Solution

Normally in Jest, we would follow [the guide on testing asynchronous code](https://jestjs.io/docs/en/asynchronous), but in this case it doesn't work because we don't have a `Promise` we can "attach" to in order to call `.then()` on.

But if we think about it, what we really want to do is **wait until all of the promises have cleared**: the `fetch` promise, the following `.json()` promise, and then our promise to call `setItems` with the new data. Once those have all resolved, _then_ we can verify the UI. We need the equivalent of [`jest.runAllTimers()`](https://jestjs.io/docs/en/jest-object#jestrunalltimers), but for promises instead of `setTimeout`, `setInterval`, etc.

Well it turns out that calling [`setImmediate`](https://nodejs.org/api/timers.html#timers_setimmediate_callback_args) will do just that; exhaust all of the promises. But since `setImmediate` uses a callback, we have to use the [callback form](https://jestjs.io/docs/en/asynchronous#callbacks) of Jest async testing:

```js {1-1,15-23}
test('new item is added to the UI when the form is successfully submitted', (done) => {
  // Instead of making a real API call, mock the helper to return a
  // resolved promise with the data that would come back from the API
  submitNewItem.mockResolvedValueOnce({ id: 14, title: 'Gucci sneakers' })

  const component = mount(<Adder />)
  const preventDefault = jest.fn()

  component
    .find('[data-testid="addform-form"]')
    .simulate('submit', { preventDefault })

  expect(preventDefault).toHaveBeenCalledTimes(1)

  setImmediate(() => {
    // within `setImmediate` all of the promises have been exhausted

    component.update()
    expect(component.find('[data-testid="adder-items"]')).toHaveLength(1)

    // have to call `done` here to let Jest know the test is done
    done()
  })
})
```

So this is great! We were able to successfully test our code! But I personally don't like using the callback form of Jest async testing. I prefer using the [`async`/`await` form](https://jestjs.io/docs/en/asynchronous#asyncawait). Well, it turns out that we can turn this `setImmediate` pattern into a Promise-based helper called `runAllPromises` that will then allow us to use `async`/`await`:

```js {1-1,3-3,17-22}
const runAllPromises = () => new Promise(setImmediate)

test('new item is added to the UI when the form is successfully submitted', async () => {
  // Instead of making a real API call, mock the helper to return a
  // resolved promise with the data that would come back from the API
  submitNewItem.mockResolvedValueOnce({ id: 14, title: 'Gucci sneakers' })

  const component = mount(<Adder />)
  const preventDefault = jest.fn()

  component
    .find('[data-testid="addform-form"]')
    .simulate('submit', { preventDefault })

  expect(preventDefault).toHaveBeenCalledTimes(1)

  await runAllPromises()

  // after waiting for all the promises to be exhausted
  // we can do our UI check
  component.update()
  expect(component.find('[data-testid="adder-items"]')).toHaveLength(1)
})
```

Wow! 🎉

There's a lot of shorthand going on with `runAllPromises`. The fully written out version would be something like:

```js
const runAllPromises = () => {
  return new Promise((resolve) => {
    setImmediate(() => {
      resolve()
    })
  })
}
```

We return a `Promise` that is resolved, when the `setImmediate` callback is called.

## The React Testing Library solution

As I mentioned in my previous article, React Testing Library is all about testing the UI from the user's experience. Our users aren't submitting the form and then waiting for promises to resolve. No, **they are waiting for the UI to update**! Even though we avoided using `component.instance()` with the Enzyme-based test, we're still kind of testing implementation details knowing that we have to `runAllPromises.`

To promote user-centric testing, React Testing Library has [async utilities](https://testing-library.com/docs/dom-testing-library/api-async) that mimic the user behavior of waiting. Specifically, there is a `waitFor()` method that allows you to _wait_ until the UI is ready. Using `waitFor`, our Enzyme test would look something like this:

```js {8-9,21-25}
import { mount } from 'enzyme'
import Adder from './Adder'
import { submitNewItem } from '../utils'
import { waitFor } from '../testUtils'

jest.mock('../utils')

// test is now `async`
test('new item is added to the UI when the form is successfully submitted', async () => {
  submitNewItem.mockResolvedValueOnce({ id: 14, title: 'Gucci sneakers' })

  const component = mount(<Adder />)
  const preventDefault = jest.fn()

  component
    .find('[data-testid="addform-form"]')
    .simulate('submit', { preventDefault })

  expect(preventDefault).toHaveBeenCalledTimes(1)

  // we wait for the assertion to pass
  await waitFor(() => {
    component.update()
    expect(component.find('[data-testid="adder-items"]')).toHaveLength(1)
  })

  // more assertions here
})
```

The `waitFor()` helper uses polling to wait until the callback function you pass to it is successful.

Before I stumbled across `runAllPromises`, I actually wrote an equivalent `waitFor()` that I could use with Enzyme:

```js
export const waitFor = (callback, { interval = 50, timeout = 1000 } = {}) =>
  act(
    () =>
      new Promise((resolve, reject) => {
        const startTime = Date.now()

        const nextInterval = () => {
          setTimeout(() => {
            try {
              callback()
              resolve()
            } catch (err) {
              if (Date.now() - startTime > timeout) {
                reject(new Error('Timed out.'))
              } else {
                nextInterval()
              }
            }
          }, interval)
        }

        nextInterval()
      }),
  )
```

The way this works is that the Jest assertions, like `.toHaveLength()`, will throw an `Error` when they fail. So `waitFor()` is continuing to poll as long as the `callback()` is throwing an error (i.e. the item has not yet been rendered). Once the assertion stops throwing an error, it was successful, so `waitFor()` resolves the promise, and test execution can continue on.

By using `await`, we wait on that promise to resolve and we've waited just like our users would wait. And if the assertion continues to fail, we'll eventually hit our timeout and the promise will be rejected. And the rejected promise will throw an `Error`, so the test case will fail just like other failed assertions.

After writing `waitFor`, I went into the [source code](https://github.com/testing-library/dom-testing-library/blob/aa7ed18486c3ab92141d54819eb7f213ddc6efb4/src/wait-for.js) to see how it was implemented in React Testing Library and its surprisingly different. Outside of the additional functionality it provides, they used a `setInterval` instead of successive `setTimeout` statements like I did. I went with the `setTimeout` route because I felt it was easier to manage the final timeout that way, but I wonder if there's an override in making lots of `setTimeout` calls? It proves that **there's never a single "right way."**

One final note, in React Testing Library the [`findBy*`](https://testing-library.com/docs/dom-testing-library/api-queries#findby) queries return a promise which resolves when an element is found that matches the given query. **The `findBy` query is basically a convenience wrapper around [`waitFor`](https://testing-library.com/docs/api-async#waitfor)**. In Enzyme we could similarly create a wrapper over our `waitFor` implementation, but I still feel that `runAllPromises` solution is probably simpler, and obviously less code.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/asynchronous-testing-with-enzyme-react-jest</link>
            <guid isPermaLink="false">asynchronous-testing-with-enzyme-react-jest</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[async]]></category>
            <category><![CDATA[enzyme]]></category>
            <category><![CDATA[react-testing-library]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Wed, 15 Jul 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[The best way to learn React]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/best-way-to-learn-react</link>
            <guid isPermaLink="false">best-way-to-learn-react</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[learning]]></category>
            <category><![CDATA[tutorial]]></category>
            <category><![CDATA[workshops]]></category>
            <category><![CDATA[courses]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Mon, 29 Jun 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[React Prop Types with TypeScript]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/react-prop-types-with-typescript</link>
            <guid isPermaLink="false">react-prop-types-with-typescript</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[props]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Thu, 11 Jun 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Integrating Bugsnag into GatsbyJS and Netlify]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/integrating-bugsnag-into-gatsbyjs-netlify</link>
            <guid isPermaLink="false">integrating-bugsnag-into-gatsbyjs-netlify</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[gatsby]]></category>
            <category><![CDATA[netlify]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Fri, 05 Jun 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[ECMAScript pattern matching proposal]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/ecmascript-pattern-matching-proposal</link>
            <guid isPermaLink="false">ecmascript-pattern-matching-proposal</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[ecmascript]]></category>
            <category><![CDATA[proposals]]></category>
            <category><![CDATA[til]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Fri, 29 May 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[The Popoff Progression]]></title>
            <description><![CDATA[
As a new bootcamp or college graduate, your first job can be really critical in determining the trajectory of your career. I believe that in your first job you should seek out mentorship and training that will allow you to focus on gaining significant depth of experience in **a single technical area**. This is counter to the prevailing wisdom to gain broad experience in several different areas.

I have reviewed so many resumes and interviewed lots of candidates who were a year or 18 months into their career, but honestly didn’t appear to be any different than the next cohort of graduates. Even though they had professional exposure to lots of different technologies, when looking for their second job, they struggled. They weren't really strong in any of the technologies they had used at their first job. As a result, **they weren't shining in their interviews**. They would likely join their second company at the same level as a new grad (and the same level they were in their first company too), but with seemingly less potential.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/popoff-progression</link>
            <guid isPermaLink="false">popoff-progression</guid>
            <category><![CDATA[career]]></category>
            <category><![CDATA[growth]]></category>
            <category><![CDATA[interviewing]]></category>
            <category><![CDATA[mentorship]]></category>
            <category><![CDATA[training]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Fri, 22 May 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Introducing Minishops]]></title>
            <description><![CDATA[
If you haven't realized yet, I enjoy teaching. Up until this point, it's come in the form of mentoring and pairing at work and [speaking at conferences](/speak/) publicly.

Well, this global pandemic that's forcing most of us to shelter-in-place has canceled all of my conference speaking for the foreseeable future. This has opened up the time that I normally devoted to prepping for talks. I've used some of that time to return to [blogging](/blog/), but the majority I've put into transforming my in-person workshops into remote workshops.

I call these remote workshops [**"minishops"**](/minishops/) because they are short (aka "mini") workshops. These minishops will last only about 3 hours so that they can be very focused on just a couple of topics instead of covering many different topics to fill a whole day workshop.

]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/introducing-minishops</link>
            <guid isPermaLink="false">introducing-minishops</guid>
            <category><![CDATA[learning]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[workshops]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Mon, 18 May 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[What exactly is a "Design System"?]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/what-exactly-is-a-design-system</link>
            <guid isPermaLink="false">what-exactly-is-a-design-system</guid>
            <category><![CDATA[design-system]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[material-ui]]></category>
            <category><![CDATA[figma]]></category>
            <category><![CDATA[css]]></category>
            <category><![CDATA[typography]]></category>
            <category><![CDATA[brand]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Fri, 08 May 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[New Gatsby site!]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/new-gatsby-site</link>
            <guid isPermaLink="false">new-gatsby-site</guid>
            <category><![CDATA[gatsby]]></category>
            <category><![CDATA[performance]]></category>
            <category><![CDATA[website]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Wed, 29 Apr 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Nested string interpolation in JavaScript]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/nested-string-interpolation-in-javascript</link>
            <guid isPermaLink="false">nested-string-interpolation-in-javascript</guid>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[strings]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[interpolation]]></category>
            <category><![CDATA[template]]></category>
            <category><![CDATA[literals]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Mon, 27 Apr 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Capture DOM element screenshots in Chrome]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/capture-dom-element-screenshots-in-chrome</link>
            <guid isPermaLink="false">capture-dom-element-screenshots-in-chrome</guid>
            <category><![CDATA[devtools]]></category>
            <category><![CDATA[chrome]]></category>
            <category><![CDATA[edge]]></category>
            <category><![CDATA[chromium]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Fri, 24 Apr 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Check out react-jsonschema-form]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/check-out-react-jsonschema-form</link>
            <guid isPermaLink="false">check-out-react-jsonschema-form</guid>
            <category><![CDATA[TIL]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[forms]]></category>
            <category><![CDATA[json-schema]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Thu, 23 Apr 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[React Testing Library over Enzyme]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/react-testing-library-over-enzyme</link>
            <guid isPermaLink="false">react-testing-library-over-enzyme</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[testing]]></category>
            <category><![CDATA[react testing library]]></category>
            <category><![CDATA[enzyme]]></category>
            <category><![CDATA[RTL]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Tue, 21 Apr 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[New React useOpaqueIdentifier hook coming soon]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/new-react-use-opaque-identifier-hook-coming-soon</link>
            <guid isPermaLink="false">new-react-use-opaque-identifier-hook-coming-soon</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[hooks]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Fri, 17 Apr 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[I'm a Google Developer Expert!]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/google-developer-expert</link>
            <guid isPermaLink="false">google-developer-expert</guid>
            <category><![CDATA[google]]></category>
            <category><![CDATA[developer]]></category>
            <category><![CDATA[expert]]></category>
            <category><![CDATA[award]]></category>
            <category><![CDATA[developer-technologies]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Wed, 10 Jul 2019 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[MVP! MVP! MVP!]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/microsoft-mvp</link>
            <guid isPermaLink="false">microsoft-mvp</guid>
            <category><![CDATA[microsoft]]></category>
            <category><![CDATA[mvp]]></category>
            <category><![CDATA[award]]></category>
            <category><![CDATA[developer-technologies]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sat, 01 Dec 2018 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[New Gatsby Blog!]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/new-gatsby-blog</link>
            <guid isPermaLink="false">new-gatsby-blog</guid>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Fri, 04 May 2018 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[12 tricks for ES6 fun]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/learning-es6-12-tricks-for-es6-fun</link>
            <guid isPermaLink="false">learning-es6-12-tricks-for-es6-fun</guid>
            <category><![CDATA[ecmascript-6]]></category>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[learning-es6]]></category>
            <category><![CDATA[tricks]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Tue, 25 Oct 2016 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Speaking at NodeSummit 2016]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/nodesummit-2016</link>
            <guid isPermaLink="false">nodesummit-2016</guid>
            <category><![CDATA[conferences]]></category>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[speaking]]></category>
            <category><![CDATA[talks]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Fri, 23 Sep 2016 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Front Porch Austin 2016]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/front-porch-austin-2016</link>
            <guid isPermaLink="false">front-porch-austin-2016</guid>
            <category><![CDATA[conferences]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[speaking]]></category>
            <category><![CDATA[talks]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Mon, 19 Sep 2016 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[NDC Oslo 2016]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/ndc-oslo-2016</link>
            <guid isPermaLink="false">ndc-oslo-2016</guid>
            <category><![CDATA[conferences]]></category>
            <category><![CDATA[html5]]></category>
            <category><![CDATA[css3]]></category>
            <category><![CDATA[speaking]]></category>
            <category><![CDATA[talks]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Thu, 21 Jul 2016 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[NationJS Node Day 2016]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/nationjs-nodeday-2016</link>
            <guid isPermaLink="false">nationjs-nodeday-2016</guid>
            <category><![CDATA[conferences]]></category>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[speaking]]></category>
            <category><![CDATA[talks]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 12 Jun 2016 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Generators as iterators]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/learning-es6-generators-as-iterators</link>
            <guid isPermaLink="false">learning-es6-generators-as-iterators</guid>
            <category><![CDATA[ecmascript-6]]></category>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[generators]]></category>
            <category><![CDATA[iterables]]></category>
            <category><![CDATA[iterators]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[learning-es6]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Wed, 13 Jan 2016 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Iterators & iterables]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/learning-es6-iterators-iterables</link>
            <guid isPermaLink="false">learning-es6-iterators-iterables</guid>
            <category><![CDATA[ecmascript-6]]></category>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[iterables]]></category>
            <category><![CDATA[iterators]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[learning-es6]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 27 Dec 2015 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[New collections]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/learning-es6-new-collections</link>
            <guid isPermaLink="false">learning-es6-new-collections</guid>
            <category><![CDATA[ecmascript-6]]></category>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[learning-es6]]></category>
            <category><![CDATA[map]]></category>
            <category><![CDATA[set]]></category>
            <category><![CDATA[weakmap]]></category>
            <category><![CDATA[weakset]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 20 Dec 2015 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Classes]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/learning-es6-classes</link>
            <guid isPermaLink="false">learning-es6-classes</guid>
            <category><![CDATA[ecmascript-6]]></category>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[learning-es6]]></category>
            <category><![CDATA[classes]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Fri, 11 Dec 2015 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[for-of loop]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/learning-es6-for-of-loop</link>
            <guid isPermaLink="false">learning-es6-for-of-loop</guid>
            <category><![CDATA[ecmascript-6]]></category>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[learning-es6]]></category>
            <category><![CDATA[for-of]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Mon, 30 Nov 2015 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Little Rock Tech Fest 2015]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/little-rock-tech-fest-2015</link>
            <guid isPermaLink="false">little-rock-tech-fest-2015</guid>
            <category><![CDATA[conferences]]></category>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[speaking]]></category>
            <category><![CDATA[talks]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 22 Nov 2015 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Nodevember 2015]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/nodevember-2015</link>
            <guid isPermaLink="false">nodevember-2015</guid>
            <category><![CDATA[conferences]]></category>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[speaking]]></category>
            <category><![CDATA[talks]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 22 Nov 2015 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Promises]]></title>
            <description><![CDATA[
Like clockwork the [_Learning ES6_ series](/learning-es6-series/) continues on, looking at _promises_. It will be the first feature we've looked at in this series that is more than syntactic sugar. But promises aren't new to JavaScript. They've existed for quite some time in helper libraries. ECMAScript 6 now brings native promise support to JavaScript via the `Promise` API. Let's jump right in!

## TL;DR

A promise represents the eventual result of an asynchronous operation. Instead of registering a callback in the call to an async function, the function returns a promise. The caller registers callbacks with the promise to receive either a promise's eventual value from the async operation or the reason why the promise cannot be fulfilled.

```js
// Creating a promise wrapper for setTimeout
function wait(delay = 0) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, delay)
  })
}

// Using a promise
wait(3000)
  .then(() => {
    console.log('3 seconds have passed!')
    return wait(2000)
  })
  .then(() => {
    console.log('5 seconds have passed!')
    x++ // ReferenceError triggers `catch`
  })
  .catch((error) => {
    // output: ReferenceError
    console.log(error)
  })
  .then(() => {
    // simulate `finally` clause
    console.log('clean up')
  })
```

Did you notice the use of [default parameters](/blog/learning-es6-parameter-handling/) and [arrow functions](/blog/learning-es6-arrow-functions/) too? If you're unfamiliar with those ES6 features, you should check out the articles detailing how they work. Interested in learning more about ES6 promises? Clone the [_Learning ES6_ Github repo](https://github.com/benmvp/learning-es6) and take a look at the [promises code examples](https://learning-es6.benmvp.com/#promises) page showing off the features in greater detail.

Well you've come this far. You might as well keep going!

## Asynchronous programming background

Because JavaScript originated as a programming language for the web, asynchronous programming has existed in it since its inception. Program execution couldn't wait for user interactions (such as clicks and key presses) before continuing like you would see in console applications. Asynchronous programming in JavaScript provides mechanisms for an application to be notified when events it cares about have just happened.

### Event handlers

Event handlers are what I call the first generation of asynchronous programming in JavaScript. You simply assigned a function to an event property and it was called whenever that event happened. Here's the event handler way of making an XHR request.

```js
var url = '/json/data.json',
  request = new XMLHttpRequest()

request.open('GET', url)

request.onload = function () {
  if (request.status === 200) {
    try {
      var responseJson = JSON.parse(request.responseText)

      // do something with daa
    } catch (e) {
      console.error(e)
    }
  } else {
    console.error('request failed!')
  }
}

request.onerror = function (e) {
  console.error(e)
}

try {
  request.send()
} catch (e) {
  console.error(e)
}
```

This style is so old that it may actually be unfamiliar for some JavaScript developers. Most developers nowadays are used to callbacks.

### Callbacks

JavaScript libraries, like jQuery, aimed to ease development pains by hiding event handlers behind functions that called a specified _callback_ function when the event was trigged. This programming style of using callbacks is also called _continuation-passing style_ (CPS) because the next step (the continuation) is explicitly passed in as a parameter:

```js
function fetch(url, callback) {
  var request = new XMLHttpRequest()

  request.open('GET', url)

  request.onload = function () {
    var data, error

    if (reques.status === 200) {
      data = request.responseText
    } else {
      error = new Error('request failed!')
    }

    callback({ data: data, error: error })
  }

  request.onerror = function (e) {
    callback({ error: e })
  }

  try {
    request.send()
  } catch (e) {
    callback({ error: e })
  }
}

fetch('/json/data.json', function (responseObj) {
  if (!responseObj.error) {
    try {
      console.log('data!', JSON.parse(responseObj.data))
    } catch (e) {
      console.error(e)
    }
  } else {
    console.error(responseObj.error)
  }
})
```

The callback pattern, while more convenient to use than event handlers, still had several drawbacks. The first is apparent in the example. The callback function has two ways of handling errors: `if-else` on the returned data and `try-catch` around any operations within the function.

Secondly, callback functions proved to be untenable when developers had callbacks within callback within callbacks. This affectionately became known as _callback hell_. Let's say for example after you retrieved `/json/data.json` you needed to make another `fetch` request _based_ on the returned data from the first request:

```js
fetch('/json/data.json', function (responseObj) {
  if (!responseObj.error) {
    try {
      var data = JSON.parse(responseObj.data)

      console.log('main data', data)

      // now call `fetch` again to retrieve new data
      // based on the response data
      fetch(data.url, function (responseObjInner) {
        if (!responseObjInner.error) {
          console.log('inner data', responseObjInner.data)
        } else {
          console.error(responseObjInner.error)
        }
      })
    } catch (e) {
      console.error(e)
    }
  } else {
    console.error(responseObj.error)
  }
})
```

It's already a mess and we're only two levels deep without any real implementation!

Attempting to manage multiple active callbacks is also pretty complicated. Imagine you wanted to fire off multiple `fetch` requests simultaneously and then you wanted to process the results when they are _all_ done? Or what if you wanted to time out a `fetch` request after it had run for more than 10 seconds? It's doable, but challenging with callbacks.

Enter promises.

### Promises

Promises ushered in the 3rd generation of asynchronous programming. A promise represents the eventual result of an asynchronous operation. Instead of registering a callback in the call to an async function (such as `fetch`), the function returns a promise. The caller then registers callbacks with the _promise_ (not the function) to receive either the promise's eventual value from the async operation or the reason why the promise could not be fulfilled.

ECMAScript 6 brings native promise support to JavaScript following the [Promise/A+](https://github.com/promises-aplus/promises-spec) standard. Promises have actually existed for quite some time in JavaScript as external libraries. The following libraries also follow the Promise/A+ standard:

- [RSVP.js](https://github.com/tildeio/rsvp.js/) by [Stefan Penner](https://twitter.com/stefanpenner)
- [ES6 Promise Polyfill](https://github.com/jakearchibald/es6-promise) by [Jake Archibald](https://twitter.com/jaffathecake)
- [Native Promise Only](https://github.com/getify/native-promise-only) by [Kyle Simpson](https://twitter.com/getify)
- [Q.Promise](https://github.com/kriskowal/q#using-qpromise) by [Kris Kowal](https://twitter.com/kriskowal)
- [Lie](https://github.com/calvinmetcalf/lie) by [Calvin Metcalf](https://twitter.com/CWMma)
- [ES6 Shim](https://github.com/paulmillr/es6-shim) by [Paul Miller](https://twitter.com/paulmillr)
- [when](https://github.com/cujojs/when) by [cujoJS](http://cujojs.com/)

The new [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) provides a `fetch` method that is an updated and promise-backed version of `XMLHttpRequest`. In fact, moving forward, all asynchronous APIs will be promise-backed. If we wanted to turn our callback-style `fetch` function from before to be promised-backed, we could create a poor man's version of the new Fetch API:

```js
function fetch(url) {
  // return a Promise object
  return new Promise((resolve, reject) => {
    let request = new XMLHttpRequest()

    request.open('GET', url)

    request.onload = function () {
      if (request.status === 200) {
        // fulfill the promise
        resolve(request.responseText)
      } else {
        // reject the promise
        reject(new Error('request failed!'))
      }
    }

    request.send()
  })
}

fetch('/json/data.json')
  .then((response) => {
    let data = JSON.parse(response.text)

    console.log('main data', data)

    // now call `fetch` again to retrieve new data
    // based on the response data
    return fetch(data.url)
  })
  .then((response) => {
    console.log('inner data', response)
  })
  .catch((e) => {
    // catching all failures!
    console.error(e)
  })
```

Much nicer to use, eh? Don't worry if you don't understand everything going on. We're going to spend the rest of our time breaking apart this example. You'll notice that callbacks still exist, but they are attached to the promise and not the function itself. A different promise callback is called depending on the outcome.

The error callback (`catch()`) is particularly convenient for two reasons:

1.  It's a single style of handling errors. Remember the the `if-else` and all the `try-catch` blocks in the callback-style approach? `try-catch` isn't needed in creating a `Promise` nor in handling one.
1.  You can handle the errors from executing the async request (XHR in this case) or errors introduced by handling the async request (in `then()` callbacks) from a single location (`catch()` callback).

Point #2 is one of the big reasons why jQuery's [`Deferred` object](http://api.jquery.com/category/deferred-object/) is not Promise/A+. Instead, errors in handling the async request that are uncaught are bubbled up to `window.error`. However, jQuery 3's `Deferred` object will be Promise/A+.

By the way, if you're interested in a polyfill for Fetch API, check out Github's [`whatwg-fetch`](https://github.com/github/fetch) library.

### Reactive programming

Reactive programming (built on top of functional programming) is positioning itself as the next generation of asynchronous programming. [Reactive extensions](https://github.com/Reactive-Extensions/RxJS) implements reactive programming in JavaScript. From the `README`:

> One question you may ask yourself, is why RxJS? What about Promises? Promises are good for solving asynchronous operations such as querying a service with an XMLHttpRequest, where the expected behavior is one value and then completion. The Reactive Extensions for JavaScript unifies both the world of Promises, callbacks as well as evented data such as DOM Input, Web Workers, Web Sockets. Once we have unified these concepts, this enables rich composition.

But let's not get ahead of ourselves here. Let's stick to learning about promises.

## Making a promise

A promise can be in one of the following three states:

- **Unsettled/pending** - the promise's async operation has yet to compute its result
- **Settled: fulfilled** - the promise's async operation has completed successfully and computed a result to return
- **Settled: rejected** - the promise's async operation did not complete successfully, most likely due to an error

A promise is settled (the async operation has completed) if it is either fulfilled or rejected. A promise can only transition from unsettled to settled **one** time and it remains settled. Attempting to settle an already settled promise does nothing. Here's a visualization of the (short) lifecycle of a promise from [Axel Rauschmayer](http://exploringjs.com/es6/ch_promises.html):

<Image src="https://exploringjs.com/es6/images/promises]]></description>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/learning-es6-promises</link>
            <guid isPermaLink="false">learning-es6-promises</guid>
            <category><![CDATA[ecmascript-6]]></category>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[learning-es6]]></category>
            <category><![CDATA[promises]]></category>
            <category><![CDATA[deferreds]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 27 Sep 2015 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Template literals & tagged templates]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/learning-es6-template-literals-tagged-templates</link>
            <guid isPermaLink="false">learning-es6-template-literals-tagged-templates</guid>
            <category><![CDATA[ecmascript-6]]></category>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[learning-es6]]></category>
            <category><![CDATA[template-literals]]></category>
            <category><![CDATA[tagged-templates]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Thu, 17 Sep 2015 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Enhanced object literals]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/learning-es6-enhanced-object-literals</link>
            <guid isPermaLink="false">learning-es6-enhanced-object-literals</guid>
            <category><![CDATA[ecmascript-6]]></category>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[learning-es6]]></category>
            <category><![CDATA[object-literals]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 13 Sep 2015 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Parameter handling]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/learning-es6-parameter-handling</link>
            <guid isPermaLink="false">learning-es6-parameter-handling</guid>
            <category><![CDATA[ecmascript-6]]></category>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[learning-es6]]></category>
            <category><![CDATA[default-parameters]]></category>
            <category><![CDATA[rest-parameters]]></category>
            <category><![CDATA[rest-operator]]></category>
            <category><![CDATA[spread-operator]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Fri, 11 Sep 2015 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Destructuring]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/learning-es6-destructuring</link>
            <guid isPermaLink="false">learning-es6-destructuring</guid>
            <category><![CDATA[ecmascript-6]]></category>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[learning-es6]]></category>
            <category><![CDATA[destructuring]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Wed, 02 Sep 2015 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Speaking at Little Rock Tech Fest 2015!]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/speaking-at-little-rock-tech-fest-2015</link>
            <guid isPermaLink="false">speaking-at-little-rock-tech-fest-2015</guid>
            <category><![CDATA[ecmascript-6]]></category>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[learning-es6]]></category>
            <category><![CDATA[default-parameters]]></category>
            <category><![CDATA[rest-parameters]]></category>
            <category><![CDATA[rest-operator]]></category>
            <category><![CDATA[spread-operator]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Wed, 02 Sep 2015 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Block-level scoping with let and const]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/learning-es6-block-level-scoping-let-const</link>
            <guid isPermaLink="false">learning-es6-block-level-scoping-let-const</guid>
            <category><![CDATA[ecmascript-6]]></category>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[learning-es6]]></category>
            <category><![CDATA[block-scoping]]></category>
            <category><![CDATA[const]]></category>
            <category><![CDATA[let]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 30 Aug 2015 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Arrow functions]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/learning-es6-arrow-functions</link>
            <guid isPermaLink="false">learning-es6-arrow-functions</guid>
            <category><![CDATA[ecmascript-6]]></category>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[learning-es6]]></category>
            <category><![CDATA[arrow-functions]]></category>
            <category><![CDATA[fat-arrow]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sun, 23 Aug 2015 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[20 reasons to drop IE8 like it's hot]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/20-reasons-to-drop-ie8-like-its-hot</link>
            <guid isPermaLink="false">20-reasons-to-drop-ie8-like-its-hot</guid>
            <category><![CDATA[browsers]]></category>
            <category><![CDATA[chrome]]></category>
            <category><![CDATA[css3]]></category>
            <category><![CDATA[edge]]></category>
            <category><![CDATA[es5]]></category>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[firefox]]></category>
            <category><![CDATA[html5]]></category>
            <category><![CDATA[ie10]]></category>
            <category><![CDATA[ie8]]></category>
            <category><![CDATA[ie9]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[opera]]></category>
            <category><![CDATA[safari]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sat, 15 Aug 2015 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Using ES6 right now]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/learning-es6-using-es6-right-now</link>
            <guid isPermaLink="false">learning-es6-using-es6-right-now</guid>
            <category><![CDATA[ecmascript-6]]></category>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[learning-es6]]></category>
            <category><![CDATA[transpilers]]></category>
            <category><![CDATA[babel]]></category>
            <category><![CDATA[traceur]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Thu, 06 Aug 2015 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Goals & Features of ECMAScript 6]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/learning-es6-goals-features-ecmascript-6</link>
            <guid isPermaLink="false">learning-es6-goals-features-ecmascript-6</guid>
            <category><![CDATA[ecmascript-6]]></category>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[learning-es6]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Sat, 01 Aug 2015 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[History of ECMAScript]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/learning-es6-history-of-ecmascript</link>
            <guid isPermaLink="false">learning-es6-history-of-ecmascript</guid>
            <category><![CDATA[ecmascript-6]]></category>
            <category><![CDATA[es6]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[learning-es6]]></category>
            <category><![CDATA[history]]></category>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Wed, 29 Jul 2015 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[New Blog!]]></title>
            <link>benmvp-58narrjea-benmvp-dev.vercel.app/blog/new-blog</link>
            <guid isPermaLink="false">new-blog</guid>
            <dc:creator><![CDATA[Ben Ilegbodu]]></dc:creator>
            <pubDate>Mon, 20 Jul 2015 00:00:00 GMT</pubDate>
        </item>
    </channel>
</rss>