Blog

Posts on software development, careers, and craft.

My definition of a TypeScript-friendly library: I don’t have to “opt-in” to...

My definition of a TypeScript-friendly library: I don’t have to “opt-in” to types. It’s automatic. I call APIs, enjoy rich autocomplete support, an...

I'm trying to use @playwrightweb instead of Cypress

I'm trying to use @playwrightweb instead of Cypress. I like that Playwright has @TestingLib queries built in. But, they work differently. getBy* qu...

TypeScript decision: How should a function that calls fetch be typed

TypeScript decision: How should a function that calls fetch be typed? Options: 1. Type the return statement 2. Type the function's signature 3. Typ...

Claim: "I don't have time to write tests or types"

Claim: "I don't have time to write tests or types". Reality: They'll save you time. Skipping types and tests may save a little time today. But it w...

Problem: A TypeScript codebase with "any" everywhere

Problem: A TypeScript codebase with "any" everywhere. My first move: 1. Strongly type all HTTP calls. This ripples throughout the code in a good wa...

TypeScript tip: It's often helpful to access a union type at runtime

TypeScript tip: It's often helpful to access a union type at runtime. Solution? 1. Declare an array const 2. Use typeof to derive a union from the...

My favorite thing about file-based routing: The folder structure corresponds...

My favorite thing about file-based routing: The folder structure corresponds to the URL. This avoids decision fatigue, and makes files easy to find...

React should deprecate class components

React should deprecate class components. They’ve languished long enough. React’s API keeps growing. And many modern libraries assume you’re using h...

Yet another reason to convert your old React class components to functions:...

Yet another reason to convert your old React class components to functions: React Server Components only work with function components. (Chart from...

Server rendering JS is suddenly popular

Server rendering JS is suddenly popular. It’s not a coincidence. Smart people finally figured out how to: 1. Render JS-based components on the serv...

Why render React Server Components

Why render React Server Components? Performance. 1. Faster fetches. The server typically has a faster internet connection than your users.💨 2. Fet...

I just created my first React Server Component with @nextjs 13

I just created my first React Server Component with @nextjs 13! 😍 Here's a 90 second summary of how it works. I like how elegant the API is. I awa...

⚛️10 reasons to prefer useReducer over useState: 1

⚛️10 reasons to prefer useReducer over useState: 1. Separates reads from writes. 2. Avoids useState pitfalls. You should use functional setState to...

TypeScript tip: Sometimes a type's name conflicts with an existing identifier

TypeScript tip: Sometimes a type's name conflicts with an existing identifier. When this happens, I alias the type's name: import { Link as LinkTyp...

React in 2014: ✅Make SPAs

React in 2014: ✅Make SPAs. ✅Use create-react-app. React in 2022: ✅Make SPAs, native mobile, static, MPAs, and hybrid apps. ✅Use Vite, Next, Remix,...

This 7 second video from @kentcdodds may be the single most compelling sales...

This 7 second video from @kentcdodds may be the single most compelling sales pitch I've seen for @remix_run. Strong types, all the way from the DB...

⚛️ React tip: If state values are related, and must be kept in sync, create...

⚛️ React tip: If state values are related, and must be kept in sync, create the "derived" value on render. Example: If you have data and filteredDa...

Naming tip: "data" is rarely a good variable name

Naming tip: "data" is rarely a good variable name. Most apps contain *many* types of data, so prefer a more descriptive name.

A simple ruleset for handling React state: 1

A simple ruleset for handling React state: 1. Start local. 2. Children need it? Pass state down via props. 3. Parent/siblings need it? Cut and past...

TypeScript tip: When migrating a web app to TypeScript, strongly type HTTP...

TypeScript tip: When migrating a web app to TypeScript, strongly type HTTP responses first. HTTP responses tend to be passed throughout the app. So...

Situation: Your team’s codebase contains an anti-pattern

Situation: Your team’s codebase contains an anti-pattern. How do you keep the anti-pattern from spreading? My approach: 1. Fix all spots 2. Educate...

useCallback is often the result of a needless useEffect

useCallback is often the result of a needless useEffect. Often a useEffect can replaced by an event handler (onClick) Often a useEffect can be remo...

4 React anti-patterns: 1

4 React anti-patterns: 1. Syncing state that can be derived on render via useEffect. 2. Using useMemo/useCallback everywhere. 3. Putting nearly all...

Performance jargon: LCP: Largest Contentful Paint - How long it takes for...

Performance jargon: LCP: Largest Contentful Paint - How long it takes for the largest piece of content to show. FID: First Input Delay - How long i...

A messy codebase contains countless examples that shouldn't be copied

A messy codebase contains countless examples that shouldn't be copied. Result? Hiring more developers often just creates tech debt, faster. 👎 A co...

React is usually plenty fast by default

React is usually plenty fast by default. I find performance optimizations are rarely necessary. If a React app is slow, a common culprit is renderi...

There are good reasons to create a folder

There are good reasons to create a folder. But, here’s a bad reason: To create many files with the same name. Avoid: 👎 /user/api.js /product/api.j...

React state tip: Group related state into a single useState call (via an object)

React state tip: Group related state into a single useState call (via an object). Benefits: ✅ Less code ✅ Better readability ✅ Groups related items...

In a monorepo

In a monorepo? I just learned about syncpack. It's a simple way to enforce that all the monorepo packages use the same dependency versions. You can...

Two places I see useEffect overuse today: 1

Two places I see useEffect overuse today: 1. Fetching via HTTP. Solution? Use react-query, React Router loader, or fetch on the server if in Next,...