fix(ios): guard delayed manual keyboard did events by current keyboard state#1338
fix(ios): guard delayed manual keyboard did events by current keyboard state#1338litinskii wants to merge 1 commit intokirillzyusko:mainfrom
Conversation
|
Hey @litinskii Is this problem still actual even for |
|
1.20.7 with bug 2026-03-04.11.18.57.mov1.20.5 2026-03-04.17.10.31.mov1.20.7 with this PR 2026-03-04.10.58.30.mov1.21.0-beta.3 is it bug or it just start working in another way 2026-03-04.17.18.32.movThanks, that makes sense. I tested 1.21.0-beta.3 from npm (not from a local git tag/branch), so I can’t point to an exact repo SHA from my local clone. This can still happen in 1.21.0-beta.3 (in another way i suppose) in navigation/auto-focus flows, because didShow can only cancel willHide if both schedules belong to the same active observer instance and lifecycle window. In this race, the delayed hide is often scheduled by the previous screen observer, then the next screen mounts and schedules show. Those tasks can complete out of order, and a stale didHide may still run last after transition, resetting height/offset to 0 while keyboard is visible. So “didShow cancels previous willHide” is necessary, but not sufficient for this case. PR is focused on the stale delayed-event race during navigation/auto-focus: So “didShow cancels previous willHide” is helpful, but not always sufficient across observer lifecycle boundaries (previous screen vs next screen). Could you share the exact commit SHA used for 1.21.0-beta.3? I don’t see that tag/branch in my local clone. This is the smallest fix I found for this specific race, but I agree there may be a better long-term design. |
Sure, this is commit: 11c0dbf
Yes, because I forgot to create them 😬 Thank you for videos! It helps a lot! I'll try to analyze problem in more details (I had only a quick look). Thank you again for raising this issue and preparing solution ❤️ |
|
BTW @litinskii Don't you mind to switch to discord (nickname is kiryl.ziusko) for further communication? I think communication in messenger will be much faster and more productive 👀 |
📜 Description
Fix race condition in manual iOS
didkeyboard events introduced in #1161.When navigating between screens, keyboard events may arrive in non-linear order (
willHide->didShow->didHide). The last delayeddidHidecould incorrectly win and reset keyboard height to0, even when keyboard is already visible on the new screen.This change keeps the manual
didstrategy from #1161, but validates actual keyboard state at delayed execution time.💡 Motivation and Context
After upgrading to
1.20.6, some navigation flows started producing incorrect keyboard offset on the next screen:0Root cause: delayed
DispatchWorkItemtasks may execute out of logical order during responder/navigation transitions.This PR prevents stale delayed events from overriding current keyboard state.
Problem Statement (clear event order issue)
When navigating between screens, keyboard events can arrive in an invalid order:
keyboard hidekeyboard show endkeyboard hide endAs a result, the last processed event is
hide, keyboard height is set to0, and offset is recalculated to0.On the next screen, keyboard is visible, but bottom inset is not applied, so content goes under the keyboard.
Reproduction
Expected:
height > 0)Actual before fix:
didHidemay run last0while keyboard is still visible📢 Changelog
iOS
didevent against current keyboard visibility before emittingdidShow/didHidekeyboardDidEventID) so old delayed tasks cannot override newer statedidtasks and clean up watchers/KVO onunmountdiddispatch approach from fix: manual did events #1161 (no rollback to systemkeyboardDid*)🤔 How Has This Been Tested?
Tested manually on iOS navigation scenario with focused input:
keyboardDidHidedoes not incorrectly win0Also verified
unmountpath does not emit late delayeddidevents from removed screen observer.📸 Screenshots (if appropriate):
Before
2026-03-04.11.18.57.mov
After
2026-03-04.10.58.30.mov
📝 Checklist