question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[useDirection] Eager hook is called on every state change.

See original GitHub issue

Bug 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:closed
  • Created 2 years ago
  • Reactions:2
  • Comments:28 (7 by maintainers)

github_iconTop GitHub Comments

6reactions
dwiltcommented, Oct 11, 2021

@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:

2021-10-11 16 04 22

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.

2021-10-11 16 02 01

@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 the Root component and it did fix the performance issue. Agree with @steveruizok that this useDirection hook should have a default value for dir. 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.

3reactions
jjenzzcommented, Nov 9, 2021

I noticed that RadioGroup, RovingFocusGroup, Tabs, ToggleGroup and Toolbar all set a default value for their dir prop to ltr 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.

Read more comments on GitHub >

github_iconTop Results From Across the Web

React Hooks - Understanding Component Re-renders - Medium
When a new ticker is selected from dropdown, onChange function gets called. This function updates the state value using the setter function.
Read more >
We don't know how React state hook works
It turns out, every hook has an update queue. When you call the setState function, React doesn't call the updater function immediately, ...
Read more >
Core - Observable Hooks
React functional components are called many times during their lifecycle. ... Otherwise it uses useLayoutEffect to listen props and state changes.
Read more >
A journey through the implementation of the useState hook
the useState hook ensures React preserves the state between re-renders. hooks should not be called in loops, nested functions or conditions.
Read more >
React Hooks Tutorial: useState, useEffect, useReducer
it's a lifecycle method which runs every time a component gets new props, or a state change happens. That's the trick. If you...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found