blueprint
blueprint copied to clipboard
NumericInput causing significant performance drops in Firefox
Environment
- Package version(s): 4.6.1
- Operating System: Tested on Windows 10
- Browser name and version: Firefox 102
Code Sandbox
https://codepen.io/PurkkaKoodari/pen/mdxMNKb
The demo renders two forms: A
contains 100 NumericInput
s with constant values and a Slider
, B
is the same but with InputGroup
s. All props to the NumericInput
s are literal constants. (Using 100 inputs just to exaggerate the effect, but it's noticeable even in much smaller forms.)
Steps to reproduce
- Open the demo in Firefox (seems to be less of an issue in Chrome).
- Drag the sliders around quickly.
Actual behavior
In Firefox, the form (and slider) with NumericInput
s renders very slowly.
Expected behavior
Both sliders should move smoothly.
Cause
Looking at the Firefox profiler, the issue seems to be that React is still calling NumericInput.getDerivedStateFromProps
even when props don't change. That calls Number.prototype.toLocaleString
numerous times, which seems to be super slow on Firefox:
In our own app, NumericInput
rendering takes up ~15% of CPU time when a form containing any NumericInputs is re-rendered. This time isn't visible at all in the React profiler, as the component's aren't rendering - I believe the time is counted against the parent components instead!
Possible solution
Since getDerivedStateFromProps
doesn't use sanitizedValue
unless min
or max
are changed, moving its computation inside if (didBoundsChange)
should be a trivial improvement:
https://github.com/palantir/blueprint/blob/develop/packages/core/src/components/forms/numericInput.tsx#L235-L245
Furthermore, most of the time is spent in isFloatingPointNumericCharacter
. One could probably cache the decimal regexes per-locale for a decent perf boost. (Currently, it's re-computing the regex for each character of the input string.)
I'm happy to write a PR if you agree with the suggestions.
Thanks for the detailed performance report. I'm definitely open to PRs to improve component perf here.