Today’s issue: Healthy React components that still taste great, a decade of SolidJS, and the morning routines of great CSS animations.
Welcome to #388.
Me showing my team how React has view transitions now
It was the best of times, it was the blurst of times. Last Monday, the React team announced the React Compiler RC – then 48 hours later, they came back for an encore and dropped two new experimental features that look pretty impactful.
I’ve already shipped these to every production codebase I can get my hands on, so now feels like a good time to learn what they actually do. Let’s dive in.
React Compiler RC: We’ve written multiple stories over the past two years about how this new(ish) build-time tool “auto-memoizes” your components to improve performance and save you from the pain of manual memoization – and now it’s finally (almost) here.
This Release Candidate makes it easier to add the compiler to your projects, and it introduces new optimizations that should produce fewer re-renders and snappier UIs. Most importantly, it means that React Compiler is now “intended to be stable” and can be safely used in production 🎉.
React View Transitions: This experimental feature lets you add animations to elements by wrapping them in the new <ViewTransition>
component, like so:
<ViewTransition>
<div>animate me plz, I'm begging you</div>
</ViewTransition>
The component lets you declaratively define what to animate, and you can also define when to animate by using one of three View Transition triggers – startTransition
, useDeferredValue
, and <Suspense>
. These animations use the new startViewTransition
web API under the hood, so you can tell all your platform zealot frenemies that you’re officially a good person now.
Activity API: The new <Activity>
component lets you visually hide and deprioritize parts of your UI while preserving their state — and it’s more performant than just slapping display: none
on them. You simply mark an Activity as visible
(rendered normally) or hidden
(unmounted but with state saved in the background).
When hidden, Effects are torn down too, reducing work and avoiding bugs like background videos continuing to play when they shouldn’t. Activity
also unlocks tricks like keeping form inputs filled when a user navigates away, pre-rendering pages they might visit next, and making SSR hydration smarter.
Bottom Line: After so much talk of React on the server, it’s nice to see the client get some love like this.
![]() ![]() ![]() ![]() |
Your team waiting on another QA cycle before they can deploy
What if you could wave a magic wand and help your team immediately start shipping faster?
That’s exactly what QA Wolf has done for hundreds of companies – including Drata, who now has 86% faster QA cycles with 4x more test cases (see the case study).
Here’s how it works:
They create, maintain, and run automated Playwright tests to cover your entire application, 5x faster than anyone else
They provide unlimited parallel test runs on their infrastructure and get you pass/fail results within 3 min
You get zero flakes, because every failed test is reviewed by their team of human QA engineers
Get a personalized demo – and see how their average customer increases their release cadence by over 5x.
This free guide shows you how to implement multi-tenancy into a Supabase app with Clerk, so you can build a B2B app that’s ready to scale to the moon.
What gets logged?
class BankAccount {
constructor(initialBalance) {
this.balance = initialBalance;
this.minimumBalance = 20.00;
}
deposit(amount) {
this.balance += amount;
}
withdraw(amount) {
if (this.balance - amount <= this.minimumBalance) {
return false;
} else {
this.balance -= amount;
return true;
}
}
getBalance() {
return this.balance;
}
}
const myAccount = new BankAccount(150.00);
myAccount.deposit(0.10);
myAccount.deposit(0.20);
myAccount.withdraw(130.30);
console.log(myAccount.getBalance());
Dan Abramov wrote about impossible components, which taste just like regular components but are made from a much healthier combination of soy products and seed oils.
David Y. wrote about Investigating an [Object] not found
error in a Next.js app. These types of errors can be very tricky to solve in prod, but he shows how Sentry’s distributed tracing tools make it pretty painless. [sponsored]
TkDodo wrote about concurrent optimistic updates in React Query.
Emil Kowalski wrote about good vs great animations. The great ones wake up at 5am and listen to Jocko Willink during their cold plunge, obviously.
Spectacle is a React library for creating sleek presentations that let you live demo your code.
Expo created this new page showing you how to migrate seamlessly from CodePush to EAS Update – and considering CodePush just got axed by Microsoft for good, it’s pretty helpful. [sponsored]
The guy who brought us OneMillionCheckBoxes is back at it again with One Million Chessboards – a realtime chess MMO with 1 million chessboards running on a single server.
Nolan Lawson wrote about AI ambivalence.
bit.cloud lets you use AI to build new full-stack features as reusable components that can be installed in your team’s existing applications. Bit’s HopeAI generates high quality code, based on your dev standards and tech stack. [sponsored]
Ryan Carniato wrote about working on SolidJS for the last decade and what it’s like to be copied by all the other JavaScript frameworks he’s learned.
Andy Jiang and Luca Casonato wrote on the Deno blog about how to add JSR packages with pnpm and Yarn.
Addy Osmani wrote about avoiding skill atrophy in the age of AI, but unfortunately, he’s too late – I’ve already lost the ability to beat “Through Fire and Flames” by Dragonforce in Guitar Hero 2 on Expert Mode.
Answer: 150.29999999999998
We would expect to see 20.00, but due to floating point arithmetic in JavaScript, we get an unexpected result. To fix this issue, we can represent money as integers (e.g., cents) and use Math.round
to avoid the pitfalls of floating-point calculations. Here is the updated code:
class BankAccount {
constructor(initialBalance) {
this.balanceCents = Math.round(initialBalance * 100);
this.minimumBalanceCents = 2000;
}
deposit(amount) {
this.balanceCents += Math.round(amount * 100);
}
withdraw(amount) {
const withdrawalCents = Math.round(amount * 100);
if (
Math.round(this.balanceCents - withdrawalCents) < this.minimumBalanceCents
) {
return false;
} else {
this.balanceCents -= withdrawalCents;
return true;
}
}
getBalance() {
return this.balanceCents / 100;
}
}
const myAccount = new BankAccount(150.0);
myAccount.deposit(0.1);
myAccount.deposit(0.2);
myAccount.withdraw(130.3);
// Displaying the remaining balance, should be 20.00
console.log(myAccount.getBalance());