microsoft / microsoft/react-native-windows

[0.74] Flyout does not display when target prop reference has been disabled

Open
#13,259 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Area: Flyout Area: Pressable bug Workstream: Component Parity
Dominant language
C++
Stars
17.3k
Forks
1.2k
Avg merge
1d 13h
Merged PRs (30d)
33

Description

Problem Description

I'm working on a react-native-windows project which was just recently updated to 0.74 from 0.66. After updating we had some issues arise with our custom dropdown component. In this component, a Touchable Opacity acts as the dropdown button and a Flyout is rendered to display the list of options in the dropdown underneath the button, using the Touchable Opacity reference for the target prop.

We disable the dropdown by disabling the touchable opacity. When the component is enabled again, the flyout stops rendering in unless it is forced to re-draw. This behaviour was not present before updating to 0.74.

I've provided a reproducible example which also shows that this issue is also seen with Pressable. It seems any target reference that is disabled atleast once, will prevent the Flyout from displaying with that target. A video demo of this example can be viewed below:

https://github.com/microsoft/react-native-windows/assets/142518306/7469c5fc-3327-459d-a078-b4e1b5a4e282

Steps To Reproduce
  1. In the demo app, pressing the two buttons should bring up their respective Flyouts at first
  2. When you press the 'enable/disable' button, it changes the state isDisabled which is passed into the disabled prop of both the buttons.
  3. After you disable and re-enable the buttons, the flyout is no longer rendered in.
Current Workaround for us

We found that passing the reference object of the View component within Touchable Opacity or Pressable to the target prop in Flyout gets around the issue for now, so this issue isn't blocker for our project

CLI version

13.6.6

Environment
System:
  OS: Windows 10 10.0.19045
  CPU: (8) x64 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
  Memory: 11.31 GB / 31.69 GB
Binaries:
  Node:
    version: 18.20.2
    path: C:\Program Files\nodejs\node.EXE
  Yarn:
    version: 3.6.4
    path: C:\Program Files (x86)\Yarn\bin\yarn.CMD
  npm:
    version: 10.5.0
    path: C:\Program Files\nodejs\npm.CMD
  Watchman: Not Found
SDKs:
  Android SDK: Not Found
  Windows SDK:
    AllowDevelopmentWithoutDevLicense: Enabled
    AllowAllTrustedApps: Enabled
    Versions:
      - 10.0.18362.0
      - 10.0.19041.0
      - 10.0.22621.0
IDEs:
  Android Studio: AI-222.4459.24.2221.10121639
  Visual Studio:
    - 17.9.34728.123 (Visual Studio Professional 2022)
Languages:
  Java: Not Found
  Ruby:
    version: 2.7.0
    path: C:\Program Files\ServiceNow\agent-client-collector\embedded\bin\ruby.EXE
npmPackages:
  "@react-native-community/cli": Not Found
  react:
    installed: 18.3.1
    wanted: 18.3.1
  react-native:
    installed: 0.74.1
    wanted: 0.74.1
  react-native-windows:
    installed: 0.74.4
    wanted: 0.74.4
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: true
iOS:
  hermesEnabled: Not found
  newArchEnabled: Not found
Target Device(s)

Desktop

Visual Studio Version

Visual Studio 2022

Build Configuration

Debug

Snack, code example, screenshot, or link to a repository
Code Snippet from Demo App
import React, { useRef, useState } from 'react';
import {
  Button,
  Pressable,
  SafeAreaView,
  StyleSheet,
  Text,
  TouchableOpacity,
  View,
} from 'react-native';
import { Flyout } from 'react-native-windows';

function App(): React.JSX.Element {

  const pressableRef = useRef(null);
  const touchableOpacityRef = useRef(null);
  const [expanded1, setExpanded1] = useState(false);
  const [expanded2, setExpanded2] = useState(false);

  const [isDisabled, setIsDisabled] = useState(false);

  return (
    <SafeAreaView style={styles.container}>
      <View style={{flexDirection: 'row'}}>
        <Pressable
          onPress={() => setExpanded1(!expanded1)}
          disabled={isDisabled}
          ref={pressableRef}>
          <View style={[styles.dropdownButton, {opacity: isDisabled ? 0.2 : 0.7}]}>
            <Text>Pressable Button</Text>
          </View>
          <Flyout
            isOpen={expanded1}
            onDismiss={() => setExpanded1(false)}
            target={pressableRef.current}
            placement={'bottom-edge-aligned-left'}>
            <View style={styles.dropdown}>
              <Text>This flyout is triggered by the Pressable Component</Text>
            </View>
          </Flyout>
        </Pressable>
        <TouchableOpacity
          onPress={() => setExpanded2(!expanded2)}
          disabled={isDisabled}
          ref={touchableOpacityRef}>
          <View style={[styles.dropdownButton, {opacity: isDisabled ? 0.2 : 0.7}]}>
            <Text>Touchable Opacity</Text>
          </View>
          <Flyout
            isOpen={expanded2}
            onDismiss={() => setExpanded2(false)}
            target={touchableOpacityRef.current}
            placement={'bottom-edge-aligned-left'}>
            <View style={styles.dropdown}>
              <Text>This flyout is triggered by the Touchable Opacity Component</Text>
            </View>
          </Flyout>
        </TouchableOpacity>
      </View>
      <View style={{paddingLeft: 15}}>
        <Button
          title='enable/disable'
          onPress={() => setIsDisabled(!isDisabled)}
        />
      </View>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    marginTop: 250,
    paddingHorizontal: 24,
    flexDirection: 'row',
    alignSelf: 'center',
    alignItems: 'center',
    justifyContent: 'center',
  },
  dropdownButton : {
    height: 50,
    width: 100,
    alignSelf: 'center',
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'grey',
    marginHorizontal: 25
  },
  dropdown : {
    height: 200,
    width: 400,
    alignSelf: 'center',
    alignItems: 'center',
    justifyContent: 'center'
  }
});

export default App;

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the behavior in the demo App with Flyout targeting the Pressable and TouchableOpacity refs, then inspect the Flyout target handling involved when disabled changes. Done means both Flyouts display again after their targets are disabled and re-enabled, with regression coverage for that sequence.

Written by the indexing model from the issue text.

Assessment

Tech stack
react-native
Domain
desktop, frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.