[iOS][Fabric] A recycled Fabric iOS view can lose the Selected accessibility trait after reuse
Platform: iOSNeeds: Triage :mag:
### Description
A recycled Fabric iOS view can lose the `Selected` accessibility trait after reuse.
On Fabric iOS, `self.accessibilityTraits` is written by two places in `RCTViewComponentView updateProps`:
- `accessibilityTraits`: replaces the full bitmask from the role (does not include `Selected`)
- `accessibilityState`: ORs in `Selected`/`NotEnabled`
Both writers diff against the view's retained props. Retained props survive recycling, so a recycled view diffs new props against stale values from its previous lifecycle.
Example with three lifecycles of **one** recycled view:
1. **Button A** (role=button, selected=true): both writers fire. Traits = `Button | Selected`. ✅
2. **Plain view** (role=none, selected=false): both writers fire. Traits = `None`. ✅
3. **Button A again** (role=button, selected=true): the role changed (none → button), so the traits writer fires and sets `Button`. But retained props still hold `selected=true` from lifecycle 1, so the state writer skips. Traits = `Button` only. `Selected` is lost. ❌
### Steps to reproduce
1. Render two Views with different keys and different roles (`role="button"` and no role), both with `accessibilityState={{ selected: true }}`
2. Conditionally render one at a time; toggle between them so Fabric unmounts one and mounts the other (forcing the native view through the recycle pool)
3. Focus the recycled View in Accessibility Inspector
4. The `Selected` trait is missing
The bug fires when the recycled view's stale `_props.selected` matches the new value (`true → true`), so the `accessibilityState` diff guard skips.
#### Reproducer Steps
```sh
git clone https://github.com/cgoldsby/rn-accessibility-traits-bug.git
cd rn-accessibility-traits-bug
yarn install
cd ios && pod install && cd ..
yarn ios
```
- Open Accessibility Inspector
- Focus the target View
- Tap "Toggle Role" to switch from `role="button"` to no role (both `selected: true`)
- Accessibility Inspector shows the `Selected` trait is lost
### React Native Version
0.86.0
### Affected Platforms
Runtime - iOS
### Output of `npx @react-native-community/cli info`
```text
N/A
```
### Stacktrace or Logs
```text
N/A
```
### MANDATORY Reproducer
https://github.com/cgoldsby/rn-accessibility-traits-bug
### Screenshots and Videos
https://github.com/user-attachments/assets/3047debb-477d-44bd-88d6-7c9bd5ffff72
0 条评论