React Native中FlatList搜索项需双击触发onPress的问题排查
问题原因分析
出现两次点击才触发onPress的核心问题是焦点管理混乱:
- 主输入框的
onFocus里调用inputRef.current.blur(),但Modal弹出后系统焦点状态未完全重置,第一次点击实际是完成失焦操作,而非触发点击事件。 - 当
searchable为true时,Modal内的搜索输入框会自动获取焦点,导致第一次点击仅让搜索框失焦,第二次才触发列表项的点击。 - 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
相关产品推荐
相关产品推荐

