Skip to content

Maximum update depth exceeded via internal store dispatch in passive effects during rapid external re-renders (RenderedTicksReporter); hard crash under fast slider scrubbing #7563

Description

@gfnextplay

Versions: recharts 3.9.2, React 19.2.5, Next.js 16.2.10 (Turbopack), Chrome.

Setup: an AreaChart/LineChart inside ResponsiveContainer with XAxis, YAxis, Tooltip, CartesianGrid, and a few ReferenceLines. The parent component re-renders in response to a range slider (an "as of" time scrubber): each input event calls setState, which recomputes the chart's data array and a ReferenceLine x.

Problem 1 — hard crash under fast scrubbing. With the app calling setState once per slider input event (no throttling), a fast mouse drag (input events arrive faster than frame rate) trips React's nested update limit:

Error: Maximum update depth exceeded. ...
The above error occurred in the <RenderedTicksReporter> component.

Captured stack: RenderedTicksReporter.useEffect → store dispatchnotifyNestedSubsforceStoreRerender, firing during commitPassiveUnmountOnFiber, interleaved with the app's own dispatchSetState per slider event until the 50 nested update limit throws. In development this crashes the route to the nearest error boundary at genuine human drag speed; in a production build the same crash (minified React #185) reproduces under higher-rate event bursts.

Problem 2 — the dev warning floor. After fixing the app side — coalescing slider updates to one setState per animation frame, hoisting every static prop to module constants (margin, axisLine, tickFormatter, label objects), and memoizing the ReferenceLine elements so only genuinely data-driven props change identity — the crash is gone at any input rate. But during continuous scrubbing the dev-only "Maximum update depth exceeded" console.error still fires roughly once per 50 frames: each frame's legitimate data change (new data array + ReferenceLine x) is followed by at least one nested store dispatch from a recharts passive effect, so React's nested update counter never sees a quiet frame to reset.

Question/ask: could the axis/tick settings sync (and RenderedTicksReporter) skip dispatching when the incoming settings are value-equal to the stored ones, rather than reference-equal? That would let data-driven re-renders (animation/scrubbing use cases) complete without a nested store dispatch per frame, which both removes the dev warning floor and adds headroom against the hard crash for apps that haven't frame-coalesced their updates.

Related but distinct from #6613 (inline object props, fixed in 3.5.0) and #7463 (React 19 Suspense ref cleanup, open) — this one needs no Suspense and survives full prop identity stabilization. Happy to put together a minimal repro if useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions