<ForrigeUke uke="40" år="2026" />
Agentisk ytelse-forbedring i React-kodebase, gjenskape router-API-er og hvorfor mindre fleksibilitet er bedre i et designsystem - i denne ukas ForrigeUke.
Dette var uka for ambisiøs utvikling og savn etter CD-installasjon - og 1759 ting som skjedde i frontendverdenen!
«<ForrigeUke /> er en artikkelserie som oppsummerer hva som skjedde i frontend-verden i uka som var.»
La agenten konkurrere med seg selv
claude.ai klarte å gjøre React-kodebasen sin 3x raskere på 2 uker. Den mest betydelige endringen var at tiden før en side var klar til å skrive på, gikk fra 3,1 sekunder til 0,55 sekunder. Dette fikk de til ved å først vise brukeren en enkel tekstboks, før resten av React-appen var ferdig initialisert.

Ingen bombe at for claude.ai stod også en agent bak forbedringene. Ved å finne noen konkrete ting å måle mot, som React Commits, kunne agenten prøve å slå sine egne benchmarks. Sparringene starta i Slack, og hver Slack-tråd tok for seg en del av brukerflyten, her med et eksempel fra sparring rundt å finne gode målinger:

Det hørtes ut som utviklerne hadde det gøy med prosjektet, for det var ikke forutsigbart hva agenten klarte å finne. En agent oppdaga at syntaks-highlighting i chaten iblant kunne fryse i ett sekund. Årsaken var en tankestrek (—). Da ble teksten behandlet som en såkalt ikke-Latin-1-streng, og highlight-regexene havnet på et tregere UTF-16-format. Claude fiksa det med en PR på 20 linjer, som en (menneskelig) utvikler så kunne gi tommel opp på, så fulgte Claude opp med deployment og sjekket om ytelsen var forbedret.
De hadde altså flere sikkerhetsmekanismer. I tillegg til enhetstester, brukte de rikelig med feature-flags ved visuelle endringer. Ved utrulling av høyere risiko endringer var funksjonaliteten først tilgjengelig for ansatte, så 1% av brukere, så resten.
Er det én takeaway fra posten, er det å optimalisere ved å finne noe agenten kan måle. I posten målte de mot blant annet antall React Commits og tid til første paint. Så lot de agenten prøve å slå sitt eget tall, og tillot ikke at nye endringer kunne forverre ytelsen. Du kan lese mer om detaljene her:

How we made claude.ai 3x faster in two weeks / claude.dev Blog
Inside our performance sprint: the benchmarks Claude built, the loop each Slack thread ran, and the guardrails that let us ship 3,000 changes ...
Når routeren mangler API-et du trenger
Om du kommer fra React Router, kan det være funksjoner du savner når du går over til Next.js. En av dem er useNavigation, som gir global tilstand for navigering. Nyttig om du for eksempel vil vise en progressbar mens en ny side laster. En annen er useBlocker, som kan hindre brukeren i å navigere bort fra et skjema med ulagrede endringer.
Men den globale tilstanden ved React Routers implementering har også en ulempe: Siden all tilstand for alle navigeringer er med, må du filtrere bort det du ikke bryr deg om, som når du ikke vil vise ProgressBar ved et søk:
// 👇 I React Router kan router tilstand hentes via useNavigation
const navigation = useNavigation();
// 👇 Kan avgjøre om brukeren søker noe ved å sjekke parameter "q"
const searching =
navigation.location &&
new URLSearchParams(navigation.location.search).has("q");
// 👇 Viser ikke lastetilstand om brukeren søker på ting
return (
<div
className={navigation.state === "loading" && !searching ? "loading" : ""}Aurora Scharff viser hvordan funksjonaliteten fra useNavigation og useBlocker kan gjenskapes i Next.js med useTransition og Context, og samtidig være mer presist enn global tilstand. Du kan wrappe en navigasjon i startTransition, så isPending forteller om navigasjonen pågår:
// Forenklet eksempel basert på bloggposten
export function NavigationProvider({ children }) {
const router = useRouter();
// 👇 useTransition holder rede på laste-tilstanden
const [isPending, startTransition] = useTransition();
function navigate(href) {
// 👇 isPending er sann frem til nye side vises
startTransition(() => {
router.push(href);
});
}
return (
// 👇 Eksponerer isPending og navigate i Context som kan brukes av andre komponenter
<NavigationContext value={{ isPending, navigate }}>
{children}
</NavigationContext>
);
}
useTransition er en hook jeg ikke har brukt i prod enda, men utifra eksemplene så blir jeg fristet til å forenkle en del logikk og unngå noen useStates. Også en fin påminnelse om å ta i bruk Context for å lage noen gjenbrukbare hooks når tilstanden er relevant for flere parter.
Scharff varsler også om at å ikke implementere full global tilstand har en tradeoff. Om det skjer navigasjon utenfor navigate-funksjonen, blir ikke tilstanden i hooken oppdatert. Det er greit å misse en progressbar, men å misse en blokkering, kan føre til at en bruker mister ulagret arbeid og du får en stykk sinna tilbakemelding.

Mønstrene vist i bloggposten er også overførbare til andre scenarier enn navigasjon, så anbefaler å ta en titt:

Rebuilding React Router's Global Hooks in Next.js | Aurora Scharff
Rebuild React Router's global navigation state in Next.js, then look at what we gain and lose when the application owns the connection.
Props er ikke et designsystem
Mange komponentbibliotek gir full frihet i hva du kan sende inn av props. Men om det blir en lang liste av stil-props (enten det er direkte på style-propen eller tailwind-klasser), er det hvert fall 3 problemer:
- fort gjort å glemme en style-prop, så ting ser ikke helt likt ut
- lista er lang, så du tar ikke helt inn hvordan komponenten ser ut utifra koden
- koden følger ikke en struktur, så selv agenter kan ende opp med å fravike fra det du egentlig ønsker å få til
Her er et lite skrekkeksempel, med stiler direkte på style-propen:
<button
style="
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
white-space: nowrap;
border-radius: 0.375rem;
font-size: 0.875rem;
line-height: 1.25rem;
font-weight: 500;
transition: color 150ms, background-color 150ms, border-color 150ms,
text-decoration-color 150ms, fill 150ms, stroke 150ms;
background-color: var(--primary);
color: var(--primary-foreground);
height: 2.5rem;
padding: 0.5rem 1rem;
"
>
Save changes
</button>
Vitonsky argumenterer derfor for å samle style-propsene for en primærknapp til en gjenbrukbar komponent som kan brukes med <Button variant="primary" />.
Ingen revolusjorende idé om du er vant til å bruke komponentbiblioteker. Det jeg likte med posten, var heller at han setter ord på skillet mellom varianter og modifikatorer, hvor jeg ikke var kjent med sistnevnte betegnelse. primary er en variant av knappen, mens ting som size="xl", fullWidth eller en icon er modifikatorer, uten å endre hva slags knapp det er.
Men om de samme modifikatorene går igjen og igjen, som <Button variant="primary" size="xl" rounded elevated icon="sparkles" />, kanskje det er passende å abstrahere kombinasjonen til en ny variant <Button variant="fancy-primary" />. Dermed unngår vi den lange listen av styles vi først prøvde å unngå.
Nå tror jeg ikke vi bør slutte med fleksibilitet i designsystemer, men det er verdt å reflektere over at når du gir frihet i valg mister du også nyttig struktur. Vitonskys bloggpost kan du lese her:

Props Are Not a Design System
Most UI kits let you pass any style as a prop — radius, size, color, or a wall of Tailwind classes, whatever you need. That flexibility ...
Det var alt for denne gang. Ha en riktig fin uke! 👋
