tamagui icon indicating copy to clipboard operation
tamagui copied to clipboard

Select sometimes not working when mounted, unmounted and mounted again.

Open coycoylaniba opened this issue 2 years ago • 15 comments

https://github.com/tamagui/tamagui/assets/47078705/98f63caf-70e9-4ca9-bff7-c1998b7e9277

[email protected]

and also it sometimes it doesn't work with multiple select is on the same screen

coycoylaniba avatar Nov 11 '23 01:11 coycoylaniba

and also, the Select component is completely not working on large android device. it does not work on my xiaomi pad 5 unless i switch to split screen or picture-in-picture/

coycoylaniba avatar Nov 11 '23 03:11 coycoylaniba

I'm facing this same issue currently. I'm testing my app on vivo2015 via expo go.

Any workaround for this yet? How did you go about this? @coycoylaniba

jerrywonderr avatar Nov 25 '23 22:11 jerrywonderr

@jerrywonderr i gave up, i just made my own modal select using react-native-modal

coycoylaniba avatar Nov 25 '23 22:11 coycoylaniba

Oh! I was even thinking of running a dev build instead of using expo go, probably that would resolve the issue but I haven't got time to work on it as I'm currently writing an exam.

If you don't mind, can I see the implementation you came up with for this? @coycoylaniba

jerrywonderr avatar Nov 27 '23 18:11 jerrywonderr

@jerrywonderr here:

import { useState } from "react";
import Modal from "react-native-modal";
import { ChevronDown } from "@tamagui/lucide-icons";
import { GetProps, ScrollView, Text, View, XStack } from "tamagui";

interface SelectProps<T> extends GetProps<typeof XStack> {
  label?: string;
  _label?: GetProps<typeof Text>;
  _wrapper?: GetProps<typeof View>;
  options: T[];
  value?: T;
  onValueChange?: (value: T) => void;
}

const Select = <T,>(props: SelectProps<T>) => {
  const {
    label,
    _label = {},
    _wrapper = {},
    options,
    value,
    onValueChange,
    disabled,
    ...rest
  } = props;

  const [open, setOpen] = useState<boolean>(false);
  const [val, setVal] = useState<T>("" as T);

  const handleValueChange = (v: T) => {
    setVal(v);
    onValueChange && onValueChange(v);
    setOpen(false);
  };

  const handleClose = () => {
    setOpen(false);
  };

  return (
    <View {..._wrapper}>
      {!!label && (
        <Text fontSize="$4" mx="$2" mb="$1" {..._label}>
          {label}
        </Text>
      )}

      <XStack
        ai="center"
        h="$4"
        bg="$gray2"
        minWidth="$5"
        bw={1}
        boc="$gray7"
        br="$4"
        px={14}
        o={disabled ? 0.5 : 1}
        pressStyle={{ o: 0.75 }}
        onPress={() => setOpen(true)}
        disabled={disabled}
        {...rest}
      >
        <Text f={1} fontSize="$4">
          {value ?? val}
        </Text>
        <ChevronDown size="$1" color="$gray10" />
      </XStack>

      <Modal
        isVisible={open}
        onBackdropPress={handleClose}
        onBackButtonPress={handleClose}
        style={{ paddingVertical: 32 }}
      >
        <View w="100%" bg="white" br="$4">
          {!!label && (
            <View p="$4">
              <Text fontSize="$5">{label}</Text>
            </View>
          )}

          <ScrollView
            contentContainerStyle={{ flexGrow: 1, padding: 16, paddingTop: 0 }}
          >
            {options.map((option, i) => {
              return (
                <View
                  key={`option-${i}`}
                  py="$2"
                  pressStyle={{ o: 0.75 }}
                  onPress={() => handleValueChange(option)}
                >
                  <Text>{option}</Text>
                </View>
              );
            })}
          </ScrollView>
        </View>
      </Modal>
    </View>
  );
};

export default Select;

it looks like this: image

it's ugly lol but it gets the job done

coycoylaniba avatar Nov 27 '23 21:11 coycoylaniba

Makes sense actually. This should work for me also. Thanks. @coycoylaniba

jerrywonderr avatar Nov 28 '23 15:11 jerrywonderr

@jerrywonderr youre welcome

coycoylaniba avatar Nov 28 '23 15:11 coycoylaniba

it seems to be fixed, I wasn't able to reproduce it. I tried mounting/unmounting and also rendering multiple Selects on the same screen. also for larger screens try to change <Adapt> when attribute to cover larger screens on native as well.

if you still have the issue let me know to re-open it.

byteab avatar Jan 09 '24 10:01 byteab

This still seems to not work in [email protected], when using the select on phone adapted to a sheet.

When mounting the first select, opening it and closing it, unmounting it, and mounting another select, it opens without an overlay (even when overlays zIndex is set to a high number), then after closing it, no selects ever opens again.

XTylich avatar Mar 02 '24 15:03 XTylich

it seems to be fixed, I wasn't able to reproduce it. I tried mounting/unmounting and also rendering multiple Selects on the same screen. also for larger screens try to change <Adapt> when attribute to cover larger screens on native as well.

if you still have the issue let me know to re-open it.

Seems to be working fine on iOS, but on Android it still won't open on the second mount. 1.93.2

luciatugui avatar Apr 12 '24 10:04 luciatugui

I have this issue when conditionally rendering a component which has select and adapt inside. I’ll try to make a reproducible sample tomorrow.

ddnzcn avatar May 09 '24 12:05 ddnzcn

@jerrywonderr here:

import { useState } from "react";
import Modal from "react-native-modal";
import { ChevronDown } from "@tamagui/lucide-icons";
import { GetProps, ScrollView, Text, View, XStack } from "tamagui";

interface SelectProps<T> extends GetProps<typeof XStack> {
  label?: string;
  _label?: GetProps<typeof Text>;
  _wrapper?: GetProps<typeof View>;
  options: T[];
  value?: T;
  onValueChange?: (value: T) => void;
}

const Select = <T,>(props: SelectProps<T>) => {
  const {
    label,
    _label = {},
    _wrapper = {},
    options,
    value,
    onValueChange,
    disabled,
    ...rest
  } = props;

  const [open, setOpen] = useState<boolean>(false);
  const [val, setVal] = useState<T>("" as T);

  const handleValueChange = (v: T) => {
    setVal(v);
    onValueChange && onValueChange(v);
    setOpen(false);
  };

  const handleClose = () => {
    setOpen(false);
  };

  return (
    <View {..._wrapper}>
      {!!label && (
        <Text fontSize="$4" mx="$2" mb="$1" {..._label}>
          {label}
        </Text>
      )}

      <XStack
        ai="center"
        h="$4"
        bg="$gray2"
        minWidth="$5"
        bw={1}
        boc="$gray7"
        br="$4"
        px={14}
        o={disabled ? 0.5 : 1}
        pressStyle={{ o: 0.75 }}
        onPress={() => setOpen(true)}
        disabled={disabled}
        {...rest}
      >
        <Text f={1} fontSize="$4">
          {value ?? val}
        </Text>
        <ChevronDown size="$1" color="$gray10" />
      </XStack>

      <Modal
        isVisible={open}
        onBackdropPress={handleClose}
        onBackButtonPress={handleClose}
        style={{ paddingVertical: 32 }}
      >
        <View w="100%" bg="white" br="$4">
          {!!label && (
            <View p="$4">
              <Text fontSize="$5">{label}</Text>
            </View>
          )}

          <ScrollView
            contentContainerStyle={{ flexGrow: 1, padding: 16, paddingTop: 0 }}
          >
            {options.map((option, i) => {
              return (
                <View
                  key={`option-${i}`}
                  py="$2"
                  pressStyle={{ o: 0.75 }}
                  onPress={() => handleValueChange(option)}
                >
                  <Text>{option}</Text>
                </View>
              );
            })}
          </ScrollView>
        </View>
      </Modal>
    </View>
  );
};

export default Select;

it looks like this: image

it's ugly lol but it gets the job done

Thx for this component code, this helped me a lot.

atalayio avatar Aug 23 '24 16:08 atalayio