facebook/react
Debugging
How to actually figure out what the runtime is doing when a bug doesn't reproduce on the first try.
Where to put a console.log
The reconciler runs everywhere, so generic logs drown in noise. The places that are usually worth instrumenting:
beginWorkandcompleteWorkfor "what is the reconciler doing right now":packages/react-reconciler/src/ReactFiberBeginWork.jsandReactFiberCompleteWork.js.commitMutationEffects,commitLayoutEffects,flushPassiveEffectsfor "what is happening at commit":packages/react-reconciler/src/ReactFiberCommitWork.js.- The
renderRootSync/renderRootConcurrententry points inReactFiberWorkLoop.js. dispatchSetStateInternal/dispatchReducerActioninReactFiberHooks.jsfor "who is causing this re-render".- For SSR,
processSegmentForFizzand the encoder helpers inpackages/react-server/src/ReactFizzServer.js. - For Flight, the
serializeModel/serializeLazyValuebranches inpackages/react-server/src/ReactFlightServer.js.
Most files have __DEV__ blocks already. The Rollup replace plugin strips them in production. Keep new debug-only logs inside if (__DEV__).
React DevTools
packages/react-devtools-extensions/ is the browser extension; packages/react-devtools/ is the standalone Electron app; packages/react-devtools-shared/ is the shared core. To rebuild and load:
yarn build-for-devtools-dev
cd packages/react-devtools-extensions
yarn build:chrome:local # or :firefox:local
# Load build/chrome/ as an unpacked extensionThe DevTools "Components" panel reads the fiber tree via the hook installed by packages/react-devtools-shared/src/backend/fiber/renderer.js — that's the single most-edited file in the DevTools tree, because it has to keep up with every new fiber tag and every hook change. The Profiler panel reads commit data via packages/react-reconciler/src/ReactFiberDevToolsHook.js.
The __DEV__-only error logger
packages/react-reconciler/src/ReactFiberErrorLogger.js is what produces the "Error: Hello, undefined! ..." red console message during a render error. If you want to see the unboxed error in development, add a temporary console.error(error) there.
ReactFiberCallUserSpace.js is where React calls into user code (render functions, effects, etc.) and is wrapped to give better stack traces — useful when you want to check what was on the stack when an error fired.
Inspecting fibers
For one-off "what does this fiber tree look like" debugging:
// In any breakpoint inside the reconciler:
function dumpFiber(fiber, depth = 0) {
if (!fiber) return;
console.log(
' '.repeat(depth * 2) +
fiber.type?.name +
' tag=' +
fiber.tag +
' lanes=' +
fiber.lanes
);
dumpFiber(fiber.child, depth + 1);
dumpFiber(fiber.sibling, depth);
}fiber.tag values are listed in packages/react-reconciler/src/ReactWorkTags.js. fiber.flags in ReactFiberFlags.js. fiber.lanes are 31-bit lane sets defined in ReactFiberLane.js.
Lane / scheduling debugging
packages/react-reconciler/src/ReactFiberLane.js ships a formatLanes() helper for converting a bitmask to a readable string. It's only available in dev. Use it like:
console.log('about to render', formatLanes(workInProgressRootRenderLanes));To see the work loop's full schedule, set the global ReactDebugCurrentFrame (which exposes the in-flight fiber) and break in ReactFiberWorkLoop.js's performUnitOfWork.
Performance debugging
The reconciler emits Performance API marks in dev when enableSchedulingProfiler is on. Read them with the React Profiler tab in DevTools, or directly in the browser's Performance panel — there's a "React Performance Tracks" view introduced in React 19.2 (see packages/react-reconciler/src/ReactFiberPerformanceTrack.js).
For really fine-grained timing, the test harness lets you advance the mock scheduler by exact amounts (Scheduler.unstable_advanceTime(N)) which is more reproducible than wall time.
SSR / Flight debugging
When debugging streaming SSR or Server Components:
- Reproduce in a fixture under
fixtures/flight/orfixtures/ssr2/. They're tiny, real React apps. - Tail the actual stream output (
curl -N http://localhost:3000/) — you'll see Flight rows appear one at a time. - The wire format is documented inline in
packages/react-server/src/ReactFlightServer.js. Each row is<id>:<tag><payload>\n. Knowing the tags (Ifor module,Jfor client reference,Hfor hint,Dfor done, …) is enough to read it by hand.
Common pitfalls
actswallows errors. If your test passes when it shouldn't, your error is being silently caught byact. Useexpect(act(...)).rejectspatterns or directly inspectScheduler.log.__DEV__flags differ in tests vs source. Source uses__DEV__, but compiled bundles in--buildmode have__DEV__replaced. A bug that only shows up in production usually means a logic error inside a__DEV__block was masking it.- Channel mismatch. If a behavior reproduces in
react@experimentalbut notreact@latest, you're probably looking at a flag-gated diff. Checkpackages/shared/forks/ReactFeatureFlags.*.jsfor the flag's value per channel.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.