facebook / react

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

Bug: Quickly selecting checkboxes on iOS doesn't work correctly #31260

Open danielddb opened 6 days ago

danielddb commented 6 days ago

React version: 18.0.0 and 17.0.2

Steps To Reproduce

  1. Open https://4txdx2.csb.app/ (React 18) in a device running iOS in Safari / Chrome.
  2. Quickly tap one checkbox followed by another one.
  3. Notice that if you quickly select one checkbox followed by another one, it checks / unchecks the previous checkbox you were on on.

Link to code example:

React 18.0.0 Sandbox, Preview

React 17.0.2 Sandbox, Preview

React 16.4.0 Sandbox, Preview

The current behavior

There appears to be some sort of race condition where tapping on a controlled / uncontrolled <input type="checkbox"> quickly after tapping another checkbox updates the original checkbox you tapped rather than the checkbox that was just tapped. It appears to be a timing issue - if you wait long enough between taps, the events are fired on the correct elements.

This works in React 16 but not React 17 and 18.

The expected behavior

The checkbox state should reflect the checked state of the checkbox you tapped, not the previous checkbox you tapped.

saul-atomrigs commented 6 days ago

Hello, I think this occurs due to the async nature of the setValues, leading to possible mismatch in state updates. Solution? How about these:

  1. Add key={id} prop to <div className="checkbox-row"> --> <div className="checkbox-row" key={id}>. This ensures each checkbox is identified as unique
  2. (optional) Change parameter values to other prevValues

    function setSelectedValues(e, value) {
    const isChecked = e.target.checked;
    
    setValues((prevValues) =>
      isChecked ? [...prevValues, value] : values.filter((v) => v !== value)
    );
    }
danielddb commented 5 days ago

Thanks for the suggestion @saul-atomrigs. I went ahead and updated the implementation of the controlled checkboxes example based on your feedback. Unfortunately, the issue still persists even with the updated approach.

Moreover, it's worth noting that this bug also occurs with the uncontrolled checkboxes example I provided. This indicates that the problem isn't specific to whether the checkboxes are controlled or uncontrolled; rather, it points to an underlying issue elsewhere.

danielddb commented 5 days ago

After spending hours trying to find a solution, adding this CSS fixes it:

input[type="checkbox"],
label {
  touch-action: manipulation;
}
danielddb commented 5 days ago

The fix in my previous comment only works when you zoom in on your mobile device. If you're zoomed out, it does't work.

sambehrens commented 5 days ago

I think this occurs due to the async nature of the setValues, leading to possible mismatch in state updates. Solution? How about these:

I don't think this could be the issue, because with only two clicks, after the first click I see the state updating other things and then quickly those things that were updated revert back when the next click of a lower checkbox un-checks the first checkbox. So the state changes are getting in in the correct order.

sambehrens commented 5 days ago

The weird thing, is that in this Sandbox, Preview React 16 codesandbox on mobile, the issue doesn't exist, but if you zoom in and try quickly clicking the checkboxes in order, only one will be clicked and the others will do nothing. Then if you add the touch-action: manipulation change, it fixes it and it works completely, both zoomed out and zoomed in. Sandbox, Preview.

That indicates that it must be an issue with React 18, right?

danielddb commented 4 days ago

@sambehrens you're right, I just created the exact same Sandbox, Preview with React 16 and it works without having to zoom in or adding touch-action: manipulation! So it definitely looks like an issue with React 18 and it also appears to be in 17 too.

sambehrens commented 1 day ago

This seems like a pretty basic flaw in React, so I don't want it to get auto-closed for no activity. How do we get maintainers to acknowledge this issue?

sambehrens commented 7 hours ago

Just want to make sure that this original issue that I referenced in my issue is linked here too: #27475

sambehrens commented 7 hours ago

I just tested it on 19.0.0-beta-26f2496093-20240514 react and react-dom and the issue still exists.