[useDirection] Eager hook is called on every state change.
See original GitHub issueBug report
Current Behavior
Several components (such as the DropdownMenu
component) use the useDirection
hook.
If this hook does not receive a dir
prop, the hook reads the element’s computed styles by pulling the direction
property from the element’s computed style.
This can be expensive. As none of the elements provide a default for this prop, if used on an element that might changes very often for whatever reason, this will cause the hook to run on every frame. This was happening to me: see a before and after before I went source-code spelunking.
Before (with <Dropdown.Root>
): Video Link
After (with <Dropdown.Root dir="ltr">
): Video Link
Expected behavior
If no property is provided, the hook should stick with its first result rather than repeating the expensive job of getting the element’s computed styles.
Reproducible example
Extremely contrived https://codesandbox.io/s/nervous-jackson-plg87?file=/src/App.tsx
Suggested solution
At the risk of being a touch imperialist, I’d expect ltr
to be the default for the dir
prop.
If you do want to read the element itself to get the direction, then I’d expect that the hook did not refresh when the element changes. Specifically, I’d suggest that element
be dropped from this dependency array.
Otherwise, if you want to foreground the ltr
or rtl
choice, make it a required prop.
If none of the above are possible, I’d expect to see this flagged as a potential performance issue when leaving it undefined for components that may change often.
Your environment
Software | Name(s) | Version |
---|---|---|
Radix Package(s) | @radix-ui/react-dropdown | 0.0.22 |
React | n/a | Latest / see sandbox |
Browser | ` | |
Assistive tech | ` | |
Node | n/a | ` |
npm/yarn | ` | |
Operating System | ` |
Issue Analytics
- State:
- Created 2 years ago
- Reactions:2
- Comments:28 (7 by maintainers)
@steveruizok thank you so much for being a touch imperialist - you saved me and my dev team lots of digging around into a very large performance problem in our app. We have dozens of instances of the Radix Dropdown menu in our app:
I took the below performance recording while doing nothing in our web app. I just hit record. I didn’t even move the mouse over the application - it never left the dev tools. You can see hundreds of rAF calls clogging up the JS thread running on every frame.
@jjenzz I don’t think your performance measuring was really fair because you only have 1 instance of the dropdown menu on the page and you weren’t running the CPU at 6x slowdown. It’s a known good practice to be using 6x slowdown on the CPU when doing performance testing because you (as a developer) likely have a much faster computer than a lot of regular users.
We applied the
dir="ltr"
to theRoot
component and it did fix the performance issue. Agree with @steveruizok that thisuseDirection
hook should have a default value fordir
. As a library who probably strives to be used by large companies in production-grade applications, I’m surprised that this issue was closed saying that this performance issue wasn’t important.I noticed that
RadioGroup
,RovingFocusGroup
,Tabs
,ToggleGroup
andToolbar
all set a default value for theirdir
prop toltr
so I thought this hook wouldn’t be working for those, but just discovered they don’t use it. It’s all getting a bit confusing 🙈The provider suggestion avoids the implicit nature of all of this inheritence stuff so I’m more and more in favour of it.