A tale of two Reacts

Issue #448.December 13, 2025.2 Minute read.
Bytes

Today’s issue: The Satoshi of web dev strikes again, HTML gateway drugs, and serenading your type checker with Raining Blood.

Welcome to #448.


Eyeballs logo

The Main Thing

Luigi drowning in a pool

Average React developer this week

A tale of two Reacts

It was the best of times (for React Native developers), it was the worst of times (for React developers).

Let’s start with the worst: Researchers discovered two more critical vulnerabilities in React Server Components this week while trying to exploit the patches for last week’s React2Shell incident – a Denial of Service vulnerability and a Source Code Exposure vulnerability.

Yes we’re all in hell, but apparently it’s common for critical CVEs to uncover “follow‑up vulnerabilities” like this. The React team is promising that “just one more upgrade bro” will fix everything for good, and hopefully the latest patched version will let React developers feel joy again. Alternatively, you could just downgrade everything to React 15, dust off ye olde class components, and pretend that RSC was just one collective fever dream. Oh wait, I think Remix 3 is already working on that.

In more positive news, the React Native team is still cooking. They just shipped their seventh release of 2025 with React Native 0.83 – which doesn’t introduce any user-facing breaking changes but does come with some meaningful upgrades:

  • React 19.2 support — This brings the <Activity> and useEffectEvent APIs to React Native, which keeps it aligned with modern React while thankfully avoiding the current RSC mess.

  • Big DevTools upgrades — New Network and Performance panels let you inspect requests and trace JavaScript execution, React renders, and user timings in a single timeline. It’s basically Chrome DevTools for React Native.

  • Web platform momentum — Web Performance APIs are now stable, and IntersectionObserver landed in Canary as part of the RN team’s push to make our “write once, run anywhere” dreams come true across web and native.

Bottom Line: If only Dickens could’ve lived to see our day and write generation-defining novels about Denial of Service vulnerabilities and useEffectEvent.


CodeRabbit logo

Our Friends
(With Benefits)

A bunch of dogs meditating

When your team’s code reviews finally evolve past ‘LGTM’

Unlock tribal Knowledge in teams. Make code reviews actually fun

Most teams treat code review like a gate. Smart teams use it as a knowledge distribution system. With CodeRabbit, you turn your hidden “how we really do things here” into reusable learnings that make every PR clearer, faster, and less annoying.

Take logging. Maybe your team requires a custom logger, specific error tracking, and different log levels per environment. In practice, new code ships with random utilities, generic console.logs, or half-remembered conventions – especially under deadline pressure.

CodeRabbit catches that drift automatically and creates learnings. You define the rule once: “For app/lib/components, use logError() from @/lib/error-tracking.” From then on, CodeRabbit flags violations in PRs, so human reviewers can focus on intent instead of nitpicks.

The result: tribal knowledge becomes searchable, standards become actually enforced, and reviews stop feeling like passive-aggressive checklists.

Free for open source projects. Sign up today.


Spot the Bug logo

Spot the Bug

Sponsored by Sentry

N+1 Queries are one of the most annoying performance issues out there, but this article shows how you can eliminate them with Seer’s (Sentry’s AI debugger) automated root cause analysis tool.

import db from "./db";
import admin from "firebase-admin";
import { getUserClaimsFromCookie } from "./claims";

const { arrayUnion, arrayRemove } = admin.firestore.FieldValue

export default async function updateLessonComplete(req, res) {
  try {
    const { lessonId, completed } = req.body

    if (!lessonId) {
      throw new Error("lessonId is a required parameter");
    }

    if (!completed) {
      throw new Error("completed is a required parameter");
    }

    const claims = await getUserClaimsFromCookie(req, res);

    if (!claims) {
      throw new Error('user must be logged in')
    }

    await db.collection('lessons').doc(lessonId)
      .update({
        completed: completed === true
          ? arrayUnion(claims.uid)
          : arrayRemove(claims.uid)
      })

    res.send({ status: "success" });
  } catch (e) {
    res.status(400);
    res.send({ error: { message: e.message } });
  }
}

Cool Bits logo

Cool Bits

  1. shadcn (the Satoshi of web dev) just launched shadcn/create – which lets you build your own shadcn/ui by picking your own component library, icons, base color, fonts, etc, so you can “build something that doesn’t look like everything else.”

  2. MongoDB Skill Badges are free, focused courses and credentials that help you quickly learn and validate specific MongoDB skills – like Advanced Schema Design Patterns, CRUD Operations, Networking Security, and more. [sponsored]

  3. Former React team member, Christoph Nakazawa just released fate – a modern data client for React and tRPC that’s inspired by Relay and GraphQL and will finally solve all of your data fetching problems forever. Probably.

  4. Christian Ekrem wrote about targeting child elements in Tailwind CSS. The last time I “targeted a child” was with my water balloon launcher when I found those kids TP’ing my house on Halloween, so my expectations are high.

  5. Deno 2.6 now lets you run package binaries with a new tool called dx, which is basically the Deno-rific version of npx.

  6. Frederik Braun explained why the Sanitizer API is just setHTML() with better branding.

  7. Jeff Escalante wrote The Complete Guide to embeddable UIs for user management in 2025 on the Clerk blog. It clocks in at almost 8,000 words and compares every single possible solution – so yeah, very complete. [sponsored]

  8. TypeSlayer is a TypeScript performance benchmarking and visualization tool that looks really useful for large TS codebases – but it features a disturbing lack of Raining Blood.

  9. Simon Willison wrote about useful patterns for building HTML tools. Just be careful because some of these sound suspiciously close to being gateway drugs for htmx.

  10. Does your startup want to build on Convex’s type-safe, reactive database for free? Apply for Convex for Startups and see why dozens of YC companies have already done it. [sponsored]

  11. Thiery Michel argues that TypeScript type system is its own programming language.

  12. Someone got Gemini to generate/predict what the front page of Hacker News would look like in 2035. Disturbingly accurate, but the overall tone wasn’t quite condescending enough.


Spot the Bug logo

Spot the Bug: Solution

Sponsored by Sentry

There’s a lot of misdirection here. The bug happens with our if (!completed) check. completed is a boolean, meaning when completed is false (making it falsy), our code will throw an error. Instead, we can check if completed is of type boolean, not if it’s falsy.

if (typeof completed !== 'boolean') {
  throw new Error("completed is a required parameter");
}