Every factual claim in this course traces to something here, grouped by the module it serves and dated to the page it came from. Performance guidance goes stale unusually fast — thresholds get revised, tools get rebuilt, browser support moves — so treat a date stamp as part of the citation rather than trivia. If a source has moved on from what a lesson says, that is worth raising with your teaching agent.
What INP is, why the other two Core Web Vitals cannot see your problem, and where a number honest enough to act on actually comes from.
WhyThe definition this whole course is built on: INP “assesses a page’s overall responsiveness to user interactions by observing the latency of all click, tap, and keyboard interactions that occur throughout the lifespan of a user’s visit to a page.” Source of the 200ms/500ms thresholds at the 75th percentile, the three-phase decomposition, the rule that the highest interaction is ignored for every 50 interactions, and the explicit exclusion of scrolling, hovering and zooming. Google defines the metric, ships the browser that measures it, publishes this page, and uses Core Web Vitals as a search-ranking input — a vendor documenting its own standard. Primary source for the INP lesson.
WhyThe three current Core Web Vitals and their good thresholds in one place — LCP within 2.5 seconds, INP 200 milliseconds or less, CLS 0.1 or less — all assessed at the 75th percentile of page loads, segmented across mobile and desktop. Also the source for dating the transition: INP was promoted from experimental to pending in 2023 and became a stable Core Web Vital in 2024, replacing First Input Delay.
WhyNames the three phases used throughout this course — input delay, processing duration, presentation delay — with a definition for each, and gives the general advice that “the best general advice in optimizing event callbacks is to do as little work as possible in them.” Its yielding guidance uses setTimeout and requestAnimationFrame; it does not mention scheduler.yield, which the long-tasks article below does.
WhyThe single sentence that explains why LCP is blind to a streaming failure: “The browser will stop reporting new entries as soon as the user interacts with the page (via a tap, scroll, or keypress).” On a chat surface the first interaction is typing a prompt, so LCP has finished recording before a token exists. Also cited in the guest-in-someone-else’s-bundle lesson for the opposite angle: LCP is the host page’s metric that a grafted widget can damage, by downloading, parsing and evaluating its own code during the window the host’s largest element is painting.
WhyThe other half of why the two green metrics are green: CLS scores the largest burst of unexpected shifts in a 5-second session window over the page lifecycle, and excludes shifts within 500 milliseconds of user input, flagged hadRecentInput. A streaming answer is close to the definition of an expected shift. Note the 2023 date — the oldest of the metric definitions cited here.
WhySource of the 50-millisecond long-task definition — “any task that takes longer than 50 milliseconds is a long task” — which is the leading indicator INP lags. Also documents scheduler.yield() with browser availability given as Chrome 129+, Edge 129+, Firefox 142+, and not supported in Safari; check current support before relying on it, since that line dates from the page’s December 2024 revision.
WhyHow INP is actually computed in the browser: startTime, processingStart, processingEnd, duration, interactionId and target, with the arithmetic for splitting an interaction into input delay and handler time. Two details that change how you read your own numbers — duration is rounded to the nearest 8ms, and PerformanceObserver’s durationThreshold defaults to 104ms with a minimum of 16ms, so short interactions are invisible at the default. Marked Baseline as of December 2025, so this is newly available rather than long-settled.
WhyThe library that implements the full INP selection rule so you do not have to. The attribution build (import from web-vitals/attribution) returns inputDelay, processingDuration, presentationDelay and an interactionTarget selector, and costs about 1.5K brotli’d over the standard build by the README’s own figure. Also documents the reportAllChanges nuance that matters for INP: even with it set, each interaction is not reported — only interactions that increase INP.
WhyThe load-bearing statement for the lab-versus-field lesson: “Lab tests, even those that support script user behavior, cannot accurately predict when users will choose to interact with a page.” Also names the specific holes in Total Blocking Time as an INP proxy — it does not consider tap delay and does not consider user behaviour — and describes CrUX as a distribution over a 28-day period at the 75th percentile. Four years old and pre-dates most INP tooling; read the INP-specific parts as a floor.
WhyThe composition of the score everyone quotes: Total Blocking Time 30%, LCP 25%, CLS 25%, First Contentful Paint 10%, Speed Index 10%. INP does not appear anywhere on the page. Worth citing partly for the stale date stamp on a vendor’s own scoring documentation — the weightings have changed across versions and the page says so, so verify against the Lighthouse version your CI pins rather than trusting these percentages.
WhyThe nuance that keeps “Lighthouse cannot measure INP” from being an overstatement: the timespan-mode report “now includes INP and an audit to help diagnose any responsiveness issues.” The navigation-mode performance score still does not. Also confirms INP is available in CrUX (as interaction_to_next_paint) and surfaced by PageSpeed Insights. Four years old — treat the tool list as historical and check current tooling.
WhyDefines the three Lighthouse modes. Navigation is “the (up until now) standard Lighthouse behavior: analyze the cold load of a page”; a timespan “runs Lighthouse audits over some period of time, which may or may not include a navigation” and is “a great way to capture what’s going on with a page during interactions”; snapshot audits a single point in time and cannot run most load-based performance metrics. The oldest page cited in this course.
WhyThe user-eligibility filter behind every CrUX number: a user must have usage statistic reporting enabled, sync their browser history, have no sync passphrase set, and be on desktop Chrome (Windows, macOS, ChromeOS, Linux) or Android Chrome. No Safari, no Firefox, no signed-out users. Field data from CrUX describes a filtered slice of your audience, not your audience.
WhyThe site-side eligibility rule that removes most enterprise agentic surfaces from CrUX entirely: origins and pages “must be publicly discoverable and there must be a large enough number of visitors in order to create a statistically significant dataset.” An authenticated B2B application page never qualifies, at any traffic volume — which makes your own RUM the only field instrument available.
WhyThe recording procedure the profiling lesson follows: record, interact, stop, read the activity summary where “long tasks are highlighted in red above the activity flame chart,” then use the Interactions track to align an interaction with main-thread activity and hover for the input delay / processing duration / presentation delay split. Also the source for preferring remote debugging against a physical Android device, with DevTools CPU throttling as the fallback. Primary source for the profiling lesson.
WhyThe live-metrics view: LCP, CLS and INP shown for the current page without recording, with an Interactions tab listing captured interactions, their timings, phases and scores, and an option to pull CrUX field data in for side-by-side comparison. The cheapest first step in any investigation — it tells you in seconds whether your reproduction is even hitting the slow path.
WhyWhat each track in a recording shows — Frames, Interactions, Main, Timings, Network, Animations, Layout shifts, GPU. The Interactions track draws whiskers for input and presentation delays, hovering gives the three-phase tooltip, and clicking an interaction carrying an INP warning shows the breakdown in the Summary tab. Timings surfaces your own performance.mark() and performance.measure() calls, which is how you make a chunk-to-commit boundary visible instead of inferred.
WhyThe announcement behind the live-metrics view, including “a real time log of all eligible interactions that occur while DevTools is open,” each entry naming the interaction type as pointer or keyboard. Carries its own caveat about lab-versus-field divergence and the need to configure device type, CPU throttling and network settings deliberately rather than measuring your own machine.
WhyCPU throttling calibration: “You can now automatically calibrate and get two additional CPU throttling presets that more accurately approximate low- and mid-tier mobile devices.” Run it once from the Performance panel’s CPU throttling dropdown. Prefer a calibrated preset to a raw multiplier — a raw 4x means a different machine on every laptop, which makes numbers uncomparable between colleagues. The same page notes Chrome 126 added the ability to throttle the CPU by 20 times.
WhyWhere the calibration flow lives in Settings, and how to run it. Cited with a caveat: this page does not itself enumerate the CPU throttling multipliers, so the numbers in this course come from the Chrome 134 release notes rather than from here.
Every source in this group is react.dev — Meta documenting its own library, its own compiler and its own scheduling model, with no independent standards body behind any of it. That is worth holding onto, because these pages are unusually good at stating their own limits, and this module leans on those limit statements more than on the features they describe. The one non-Meta source is Vercel, documenting an SDK it sells the platform for. The claim that a memo boundary and the compiler operate on render cost while the ref-and-flush pattern operates on render count is this course’s own framing, not a distinction any of these pages draws.
WhyThe precondition the memoization-theatre lesson turns on, in React’s own words: a memoized component “will usually not be re-rendered when its parent component is re-rendered as long as its props have not changed,” with props compared per-prop by Object.is. Also the sentence that decides the streaming case — memo “is completely useless if the props passed to your component are always different, such as if you pass an object or a plain function defined during rendering” — and the caveat that “memoization is a performance optimization, not a guarantee.” Primary source for the memoization-theatre lesson. Note what it does not say: it gives no cost figure for a failed comparison, which is why this course gives none either.
WhyThe compiler works by “handling memoization for you, eliminating the need for manual useMemo, useCallback, and React.memo,” and names the two problems it targets: re-renders propagating to components that did not change, and expensive calculations repeating. Primary source for the compiler-does-not-fix-this lesson, cited for what it claims rather than for what it is often reported to claim — nothing on the page states that the compiler changes how often a state update causes a render, which is the whole of that lesson’s argument.
WhyDates the compiler’s stable release. Cited so the compiler lesson can say “stable since 7 October 2025” rather than repeating the “still experimental” framing that was accurate in 2024 and is not now. This course’s standing rule is that every status claim carries a date; this is that date.
WhyThe dating check behind the compiler lesson: React Compiler reached beta on 21 October 2024 and 1.0 on 7 October 2025, and React 19.2 is the current stable line. Already cited by this course’s first module; it appears again here because the compiler’s status changed twice in a year and undated advice about it is the most common stale claim in this subject.
WhyThe single guarantee the ref-and-flush pattern rests on: “Changing a ref does not trigger a re-render,” explained as “React is not aware of when you change it because a ref is a plain JavaScript object.” Also the caveat that keeps the pattern sound — “Do not write or read ref.current during rendering… Reading or writing a ref during rendering breaks these expectations” — which a buffer-in-a-ref invites you to violate. Primary source for the keeping-the-stream-out-of-state lesson.
WhyThe subscribe / getSnapshot / getServerSnapshot contract, the requirement that getSnapshot return an Object.is-stable value while the store is unchanged, and the failure React names in its own error text when it does not — the result of getSnapshot should be cached, followed by an infinite render loop. Also React’s own priority order, which the lesson leads with rather than buries: prefer useState and useReducer, and reach for this hook only to integrate with existing non-React code. Carries the Transition caveat that hands off to the last lesson: a store mutated during a non-blocking Transition makes React fall back to performing that update as blocking. Primary source for the external-store lesson.
WhyThe interruption guarantee a stop button depends on: “A state update marked as a Transition will be interrupted by other state updates… React will restart the rendering work on the chart component after handling the input update.” Restart, not resume — which is the degradation the transitions lesson is built around. Also the documented async limitation: state updates issued after an async request must be wrapped in another startTransition to count as Transitions, described by React as a known limitation it intends to fix. Primary source for the transitions lesson.
WhyTwo sentences the transitions lesson could not be written without. The degradation, stated by React itself: “The background re-render is interruptible: if there’s another update to the value, React will restart the background re-render from scratch… if the user is typing into an input faster than a chart receiving its deferred value can re-render, the chart will only re-render after the user stops typing.” Substitute a token stream for the typing and that is the perpetual-restart failure. And the boundary sentence that stops a whole class of bad proposals: deferring a value “does not make re-rendering of the SlowList faster,” it tells React the re-render can be deprioritized. Scheduling tools, not speed tools.
WhyCited for one distinction only: automatic batching coalesces multiple setState calls into a single re-render, which is a different mechanism from the priority assignment that Transitions perform. Both get invoked loosely as “React’s fix for streams,” and only batching’s absence explains why three chunks arriving in three separate tasks produce three renders however the updates are marked. The oldest source in this module — four years old at the time of writing — and cited for background rather than for current guidance.
WhyAlready the instrument behind the profiling lesson, reused here as the way to settle the memo question with a ratio rather than an argument: actualDuration “indicates how well the subtree makes use of memoization,” and baseDuration estimates the unoptimised cost, so a subtree where the two track each other has memoization that is not doing anything. Two caveats travel with every number it produces — profiling “is disabled in the production build by default,” so local figures are inflated, and it counts render work only, not the style, layout and paint that INP also includes.
WhyCited in the keeping-the-stream-out-of-state lesson as production precedent rather than as an authority: the useChat hook ships a throttle option for decoupling stream arrival rate from React update rate, which is the same pattern that lesson builds by hand. The option was introduced under an experimental_ prefix and has been renamed since, so the lesson deliberately does not print a parameter name — check it against the docs for the version you have installed. The useful signal is that a widely used chat hook needed the knob at all.
What a grafted surface costs a host page, and what it keeps costing once it is running. Almost every source here is a vendor describing its own default, its own library or its own product — highlight.js on its own bundle behaviour, react.dev on React, TanStack on TanStack Virtual, Vercel on Streamdown — which is flagged inline in each note. The one non-vendor source is a user’s production incident report, cited for its mechanism and explicitly not for its headline figure.
WhyOne sentence carries the whole example: “By default, when you import the main package, all 193 languages will be loaded automatically.” Also gives the escape hatch the fix depends on — importing highlight.js/lib/core and registering languages individually. The library documenting its own default, which is the default that costs you; the claim is checkable against your own analyzer output in a minute, and the language count is only true for the version this page currently documents. Primary source for the three-markdown-renderers lesson.
WhyThe precise wording that keeps code splitting from being oversold: lazy “lets you defer loading component’s code until it is rendered for the first time.” Defer, not remove. Also the Suspense requirement, the note that dynamic import() “might require support from your bundler or framework” — not a formality inside a host build you did not write — and the trap that matters most on a streaming surface: “Declaring lazy components inside other components will cause all state to be reset on re-renders.” Meta documenting its own library. Primary source for the guest-in-someone-else’s-bundle lesson.
WhyThe three properties that make a transcript hostile to windowing, in the maintainers’ own words: “New output appears at the end. Older history loads by prepending items at the start”; “The last message can grow token by token while the model is streaming”; and, on pinning, “if someone scrolls up to read history, incoming messages shouldn’t yank them back to the bottom, and if they’re already there, the UI should stay pinned.” TanStack is describing a problem it then sells the answer to. The reason it is still load-bearing is second-order: a mature virtualization library adding APIs specifically for this case is the maintainers stating that the general-purpose setup did not cover it. Primary source for the virtualizing-a-long-conversation lesson.
WhyThe two options built for the two hard properties: anchorTo: “end” for “prepend stability and streaming bottom growth”, and followOnAppend to “keep the viewport pinned to the end when a new message arrives and the user was already at the end”, where “if the user has scrolled up to read history, appended messages do not pull them away.” Undated, so the option names were checked against the live page rather than quoted from memory — verify again before pasting the code shape, since names in an actively developed library go stale quietly. Vendor documenting its own API.
WhyCited only for vocabulary: FixedSizeList for “a long, one-dimensional list of equally sized items”, VariableSizeList for “a list of items that have different sizes”, which “expects a function for the itemSize prop instead of a specific value”. That last phrase is the mechanism behind the jump — a size per index, resolved and cached, models items that differ from each other and not from themselves a frame later. At 29 April 2019 this is the oldest page cited anywhere in this course, older than the profiling lesson’s oldest source; it pre-dates hooks-first React and says nothing about content that resizes at runtime. Take no implementation pattern from it.
WhyThe same quadratic loop this lesson describes, in a shipped product and on the server side: the backend “re-serializes the entire accumulated output (all prior text, reasoning blocks, tool calls, images, sources) into one HTML string and emits it via Socket.IO on every SSE event.” Cited for the mechanism only. The issue’s headline traffic-amplification multiplier is the reporter’s own arithmetic projected over an assumed cluster topology, never independently checked, and this course deliberately does not repeat it. Closed as not planned, so read it as a documented failure rather than an accepted diagnosis. Primary source for the cost-of-parsing-every-token lesson.
WhyA drop-in replacement for react-markdown built for AI streaming, cited as evidence that the problem is real and current enough for a large vendor to ship a component around it. Its docs frame the hard part as incomplete syntax rather than raw speed: it “automatically detects and completes unterminated Markdown syntax” and “applies styling to partial content as it streams in”, where an ordinary renderer “will either render these incomplete elements incorrectly or not at all.” Vercel publishes this and sells the platform it leads to. It is not evidence for any speedup figure, and nothing here documents how the library works internally — the “parse the stable prefix once” framing in the lesson is this course’s own, not a technique attributed to Streamdown.
Performance numbers go stale faster than most facts on this site — thresholds get retired, DevTools features move, browser support changes. Every claim here links to the page it came from and says when that page was last updated. If a source has moved on, check the resource list and tell your teaching agent — the course is meant to be corrected.