TextInput autoFocus causing Navigation animation glitch
Background
Recently at work, I encounter a weird animation glitch bug while navigate to a new page with keyboard focus. At first I thought it was cause by the logic of navigation, but later on it turn outs to be TextInput
.
Actual Problem
With some digging, I find out it was cause by using TextInput
's autoFocus
. And there's already a PR fixing it, thanks to @janicduplessis 's contribution. In summary, requestAnimationFrame
causes the focus command to be sent in the same batch as starting screen transitions.
More in @janicduplessis point of view
Looking at the iOS code I don't see how a race could happen since it calls UIManager.focus which then uses addUIBlock to focus the input. All the operation should happen in order so the new input will always be created and attached before focus is called. On android it uses dispatchViewManagerCommand which uses UIViewOperationQueue so it will also be properly synced with view creating operations.
Might have been a workaround for an old race condition bug that was since then fixed.
It seems like a bug with UIKit, It must assume keyboard focus will happen in the same event loop as the transition. Normally you'd call becomeFirstResponder in viewWillAppear. This will cause the keyboard to slide in from right to left smoothly with the new screen animation. When removing the raF it will cause pretty much the same thing to happen.
Just tested on Android and it causes the keyboard to open then close immediately :( This explains why this was added.
How to fix it?
This really depends on which RN version you're in. If you're usingv0.62.0-rc.0
, then good news is it's already fixed.
But to upgrade to the latest RN version isn't that easy, so my suggestion is to do the autoFocus
manually. By calling focus()
manually in componentdidmount
and set some delay with setTimeout()
should do the trick.
Follow up
In the recent commit of RN, JS implementation on autoFocus
has been removed. We no longer need to call focus on mount from JS as both iOS and Android implements it natively now.