You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native中FlatList搜索项需双击触发onPress的问题排查

问题原因分析

出现两次点击才触发onPress的核心问题是焦点管理混乱:

  1. 主输入框的onFocus里调用inputRef.current.blur(),但Modal弹出后系统焦点状态未完全重置,第一次点击实际是完成失焦操作,而非触发点击事件。
  2. 当searchable为true时,Modal内的搜索输入框会自动获取焦点,导致第一次点击仅让搜索框失焦,第二次才触发列表项的点击。
  3. FlatList的keyboardShouldPersistTaps配置虽设为always,但未从根源解决焦点抢占的问题。
解决方案及代码修改

通过以下几点调整,实现单次点击触发列表项的onPress:

1. 禁止搜索输入框自动获焦

给Modal内的搜索TextInput添加autoFocus={false},避免Modal弹出时自动抢占焦点:

<TextInput
  ref={searchRef}
  autoFocus={false} // 新增:禁止自动获焦
  mode="outlined"
  outlineColor="#68c25a"
  activeOutlineColor="#68c25a"
  style={styles.modalSearch}
  value={query}
  onChangeText={(q) => setQuery(q)}
  placeholder="Search"
  right={
    <TextInput.Icon
      name="close"
      color="#68c25a"
      onPress={() => {
        setQuery("");
      }}
    />
  }
/>

2. 统一处理Modal弹出时的焦点

新增useEffect监听modalOpen状态,在Modal弹出时主动清除所有输入框的焦点:

// 新增:Modal弹出时统一处理焦点
useEffect(() => {
  if (modalOpen) {
    inputRef.current?.blur();
    searchRef.current?.blur();
  }
}, [modalOpen]);

3. 优化列表项点击逻辑顺序

将Keyboard.dismiss()放在状态更新之前,确保键盘完全关闭后再处理UI状态变更:

const renderItem = ({ item }) => {
  return (
    <Item
      item={item}
      value={selectedValue.id}
      onPress={() => {
        Keyboard.dismiss(); // 优先关闭键盘
        inputRef.current?.blur();
        searchRef.current?.blur();
        setQuery("");
        setSelectedValue(item);
        setModalOpen(false);
      }}
    />
  );
};

4. 简化主输入框的onFocus逻辑

移除主输入框onFocus里多余的blur调用,仅保留打开Modal的逻辑(焦点处理交给统一的useEffect):

<TextInput
  ref={inputRef}
  label={label}
  value={selectedValue.title}
  style={styles.sheepTextInput}
  mode="outlined"
  onChangeText={(text) => onSelect(text)}
  showSoftInputOnFocus={false}
  onFocus={() => {
    setModalOpen(true); // 仅负责打开Modal
  }}
/>
完整修改后的代码
const Item = ({ item, onPress, value }) => (
  <TouchableOpacity style={styles.modalItemStyle} onPress={onPress}>
    <View style={styles.modalIconStyle}>
      {item.id === value && <Icon name="sheep" size={20} color="#68c25a" />}
    </View>
    <Text style={styles.modalItemTextStyle}>{item.title}</Text>
  </TouchableOpacity>
);

const MyDropdown = ({
  data,
  label,
  field,
  onSelect,
  value,
  searchable = true,
}) => {
  const [modalOpen, setModalOpen] = useState(false);
  const [selectedValue, setSelectedValue] = useState(value);
  const [query, setQuery] = useState("");
  const [modalData, setModalData] = useState(data);

  useEffect(() => {
    if (query.length > 0) {
      const filteredData = data.filter((item) =>
        item.title.toLowerCase().includes(query.toLowerCase())
      );
      setModalData(filteredData);
    } else {
      setModalData(data);
    }
  }, [query]);

  // 新增:Modal弹出时统一处理焦点
  useEffect(() => {
    if (modalOpen) {
      inputRef.current?.blur();
      searchRef.current?.blur();
    }
  }, [modalOpen]);

  const inputRef = useRef(null);
  const searchRef = useRef(null);

  const renderItem = ({ item }) => {
    return (
      <Item
        item={item}
        value={selectedValue.id}
        onPress={() => {
          Keyboard.dismiss();
          inputRef.current?.blur();
          searchRef.current?.blur();
          setQuery("");
          setSelectedValue(item);
          setModalOpen(false);
        }}
      />
    );
  };

  return (
    <View style={styles.selectContainer}>
      <TextInput
        ref={inputRef}
        label={label}
        value={selectedValue.title}
        style={styles.sheepTextInput}
        mode="outlined"
        onChangeText={(text) => onSelect(text)}
        showSoftInputOnFocus={false}
        onFocus={() => {
          setModalOpen(true);
        }}
      />
      <Modal height="auto" isVisible={modalOpen}>
        <View style={styles.modal}>
          {searchable && (
            <View>
              <TextInput
                ref={searchRef}
                autoFocus={false} // 禁止自动获焦
                mode="outlined"
                outlineColor="#68c25a"
                activeOutlineColor="#68c25a"
                style={styles.modalSearch}
                value={query}
                onChangeText={(q) => setQuery(q)}
                placeholder="Search"
                right={
                  <TextInput.Icon
                    name="close"
                    color="#68c25a"
                    onPress={() => {
                      setQuery("");
                    }}
                  />
                }
              />
            </View>
          )}
          <FlatList
            keyboardShouldPersistTaps="always"
            data={modalData}
            renderItem={renderItem}
            keyExtractor={(item) => item.id}
          />
        </View>
      </Modal>
    </View>
  );
};

内容的提问来源于stack exchange,提问作者Nika Bo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 12:30:44