facebook / react

The library for web and native user interfaces.
https://react.dev
MIT License
229.29k stars 46.96k forks source link

Bug: re-rendering order of onBlur and onClick inconsistent between desktop and mobile browsers #31115

Open CSalih opened 1 month ago

CSalih commented 1 month ago

React version: 18.3.1

Steps To Reproduce

  1. Open https://stackblitz.com/edit/react-onblur-onclick-re-rendering
  2. Click on the input field to focus on it
  3. Change the value in the input field (e.g. press 3)
  4. Input must be still have focus, then press the "Click Me" button

Link to code example: https://stackblitz.com/edit/react-onblur-onclick-re-rendering

The current behavior

On desktop the log looks like:

onChange
onBlur 
updateState to 2 
render App 
render App 
onClick 2 

but on mobile:

[Log] onChange
[Log] onBlur
[Log] updateState to – "2" 
[Log] onClick – 1 
[Log] render App 
[Log] render App 

This issue is reproducible on an iPad Air (4th generation) with iOS 17.5.

The expected behavior

On both desktop and mobile, clicking the button while focus is still on the input should trigger a re-render before onClick event.

MeerArsalanAli27 commented 1 month ago

It seems that mobile browsers have a different approach to handling focus and blur events, which is causing this inconsistent re-rendering behavior when you click a button while still typing in the input field. A simple yet effective fix is to use setTimeout to briefly delay the onClick event, allowing the re-rendering to complete before the event is triggered. This ensures a seamless user experience across all devices.

CSalih commented 1 month ago

Thanks for the suggestion, but using setTimeout is a workaround which doesn't feel like a good solution to this problem. While it might temporarily address the re-rendering issue, it introduces a delay in the user experience and relies on an arbitrary timeout value.

Ideally, we need to figure out why React's handling of focus and blur events differs between desktop and mobile Safari and find a way to ensure consistent behavior across all platforms. There seems to be a similar issue reported in the Preact project (https://github.com/preactjs/preact/issues/3792) which has been resolved.