-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ref.focus() doesn't work after 1st render, requires ugly workaround #9292
Comments
Many of our core contributors are taking some much needed vacation throughout December 2021. Thank you for being patient while we relax, recharge, and return to a normal responsiveness in January 2022. In the meantime feel free to continue to pose questions, open issues, and make feature requests - you just may not get a response right away. |
useEffect is called after the React component is rendered to JS, but the underlying native view is rendered later. I know ref.measure does not work correctly until the component is first presented, for example. ref.focus internally goes through UIManager.focus, which just calls TryFocusAsyc. Putting a breakpoint on the native side of that would make it a bit clearer as to what's happening. This sort of scenario seems like the kind of thing that would be useful to enable without too many hoops. Managing focus with FlatList/VirtualizedList is particularly tricky in separate ways, since items under certain conditions can be rendered asynchronously in batches, or virtualized away while still focused (that one will be fixed). |
Good to know. So is the solution here to delay the ref.focus() call with some kind of special post native view render effect hook? Kind of like useLayoutEffect but after useEffect instead of before? Or is the timeout the best we can do at the moment?
I think I found the right function and I'm hitting the breakpoint. Anything I should be looking for in particular?
Agreed. I just dealt with this and ended up writing a fairly complex helper hook to try and abstract this away so I didn't have to re-implement this focus support for every screen that has a flat list with focusable stuff inside it. But maybe you meant tricky from the RNW implementation perspective. It's probably tricky from the app author perspective and the RNW maintainer perspective :) |
Yeah, I really wish we had a hook for this... I added this hack a while back to guarantee the condition reliably, but it does have the potential to add some latency.
Not being able to focus synchronously itself opens up to race conditions. E.g. the UI thread could move focus by keyboard or screenreader before
This would let us know the state of the view tree, when we are trying to focus with |
We can see then that a ShadowNode exists with a view, and a parent shadow node, but the view doesn't have a parent. This means for the So we cannot focus the component, because the UIElement hasn't been attached to the window's view tree yet. This feels a little bit funky to me, but I'm not sure how much of this lifetime is controlled by us vs React/RN. I think @acoates-ms did a lot of the work for this before my time. |
The way we've worked around this in the past, e.g., for |
Do any of the other platforms have to handle this case where there's a timing difference between the nodes being available and the focus request? I don't believe XAML has a way to declare the focus presence up front. This needs some thought for how to fix reliably. |
I think the workaround described above could fix things pretty reliably - keeping a deferred focus state in UIManager in case imperative focus is called on a view that has not been loaded, and leveraging the same code for any autoFocus behaviors, e.g., for TextInput or Flyout. In terms of how other platforms handle this, I think TextInput is the best example. I'm guessing the |
I think the queue-based solution is a good one. If a focus request comes in, on something not yet connected, we buffer subsequent UIManager focus/blur requests until the next is available. That would preserve app-side focus state correctly, as well. |
We would want to replay the list of focus transitions within the same batch of work, for atomicity. But if that is replayed, synchronously on UI thread before other intersecting work, the focus state will maintain correctness. |
An edge case is if native focus state mutates in between the |
Unassigned currently. Due to release timeline; moving to 71. |
Flagging. Issue has had a milestone since 69 but remains unassigned. Let's assign to a dev or issue should be moved to backlog. |
Moving this to the backlog until someone hits this with an up-to-date version of RNW. |
Problem Description
Calling ref.focus() on a touchable or pressable component doesn't work right away.
But if you set a 1ms timeout and then try again, it works.
More details in the README of repro of this issue I posted
May be related to being a child of a flat list. This doesn't seem to happen in simpler screens that don't have a flat list (i.e. just a plain old screen with a few buttons and manually managed refs). But in the flat list scenario it happens consistently.
Steps To Reproduce
More details in the comments of App.js
Expected Results
More details in the comments of App.js
CLI version
6.3.1
Environment
Target Platform Version
10.0.19041
Target Device(s)
Xbox
Visual Studio Version
Visual Studio 2019
Build Configuration
Debug
Snack, code example, screenshot, or link to a repository
https://github.com/luisnaranjo733/rnw-66-focus-issue
The text was updated successfully, but these errors were encountered: