React Native中TextInput无法聚焦问题求助及代码排查
药品查询APP TextInput无法获取焦点问题排查与修复
我正在开发一款小型药品查询APP,本地通过medicines.js存储了包含药品名称、缩略图及图片地址的数据,同时配有相关图片资源。首页顶部设置了TextInput搜索框用于筛选药品,默认展示包含企业图片和可跳转至药品列表页的TouchableOpacity的HomeContent组件。目前遇到的问题是:TextInput无法获得焦点,无报错信息,但HomeContent中的TouchableOpacity可正常响应。
相关代码
HomeScreen 代码
import { View, SafeAreaView, StatusBar, TextInput, Pressable, Image, Keyboard, Text, TouchableOpacity, FlatList, } from "react-native"; import React, { useState, useEffect, useRef } from "react"; import SearchList from "../components/SearchList"; import HomeContent from "../components/HomeContent"; import { medicines } from "../files/allMedicines"; const HomeScreen = ({ navigation }) => { const [typeData, setTypeData] = useState(""); const [allMedicines, setAllMedicines] = useState([]); const [showMainContent, setShowMainContent] = useState(""); useEffect(() => { setAllMedicines(medicines); setShowMainContent(true); }, []); const typingData = (value) => { setShowMainContent(false); setTypeData(value); if (value.length > 1) { return setAllMedicines( medicines.filter((medi) => medi.name.toLowerCase().includes(value.toLowerCase()) ) ); } else if (value.length == 1) { setAllMedicines("Type medicine name"); } else { setAllMedicines(medicines); } }; const closeSearchList = () => { Keyboard.dismiss(); console.log("close pressed"); setShowMainContent(true); setTypeData(""); setAllMedicines(""); }; return ( <SafeAreaView style={{ flex: 1, marginTop: 0, backgroundColor: "#6ab187" }}> <StatusBar backgroundColor="#6ab187" /> <View style={{ width: "100%", height: 60, backgroundColor: "#098", flexDirection: "row", alignItems: "center", justifyContent: "center", }} > <TextInput placeholder="search" onFocus={() => setShowMainContent(false)} onBlur={() => setShowMainContent(true)} onChangeText={(data) => typingData(data)} value={typeData} style={{ width: 280, height: 50, backgroundColor: "#fff", fontSize: 25, textTransform: "uppercase", borderTopLeftRadius: 15, borderBottomLeftRadius: 15, paddingLeft: 10, color: "#098", }} /> <Pressable onPress={() => closeSearchList()}> <Image source={require("../assets/icons/close.png")} style={{ width: 50, height: 50, backgroundColor: "#fff", borderTopRightRadius: 20, borderBottomRightRadius: 20, }} /> </Pressable> </View> <View style={{ flex: 1 }}> {showMainContent ? ( <HomeContent navigation={navigation} /> ) : ( <SearchList navigation={navigation} allMedicines={allMedicines} /> )} </View> </SafeAreaView> ); }; export default HomeScreen;
HomeContent 代码
import React from "react"; import { View, Text, Image, TouchableOpacity } from "react-native"; const HomeContent = ({ navigation }) => { return ( <View style={{ flex: 1}}> <View style={{ flex: 2, alignSelf: "center", justifyContent: "center", alignitems: "center", paddingHorizontal: 5, }} > <Image source={require("../assets/images/1.png")} style={{ width: "96%", aspectRatio: 0.8, resizeMode: "contain", }} /> </View> <View style={{ flex: 1, alignItems: "center", justifyContent: "flex-start", }} > <TouchableOpacity style={{ width: 200, height: 50, padding: 5, backgroundColor: "#098", alignItems: "center", justifyContent: "center", borderRadius: 20, }} onPress={() => navigation.navigate("AllMedicines")} > <Text style={{ color: "#fff", fontSize: 25, fontWeight: 500 }}> All Medicines </Text> </TouchableOpacity> </View> </View> ); }; export default HomeContent;
SearchList 代码
import { View, Text, FlatList, TouchableOpacity, Image } from "react-native"; import React from "react"; const SearchList = ({ navigation, allMedicines }) => { return ( <View style={{ flex: 1 }}> <FlatList style={{ flex: 1, width: "100%" }} data={allMedicines} renderItem={({ item }) => { return ( <View style={{ flex: 1, justifyContent: "center", alignItems: "center", }} > <TouchableOpacity style={{ width: "90%", }} onPress={() => navigation.navigate("MedicineDetail", { imagePath: item.image, }) } > <View style={{ width: "100%", flexDirection: "row", marginVertical: 5, backgroundColor: "#263", borderRadius: 10, padding: 10, alignItems: "center", justifyContent: "space-between", shadowColor: "#171717", shadowOffset: { width: -2, height: 4 }, shadowOpacity: 0.9, shadowRadius: 3, }} > <Text style={{ fontSize: 25, color: "#fff", }} > {item.name} </Text> <View> <Image source={item.thumb} style={{ width: 40, height: 40, resizeMode: "contain" }} /> </View> </View> </TouchableOpacity> </View> ); }} /> </View> ); }; export default SearchList;
问题排查与修复方案
1. 状态逻辑冲突导致焦点丢失
当前TextInput的onFocus事件会立即切换showMainContent为false,触发组件重新渲染,此时TextInput还未完全获取焦点就被重建,直接导致焦点丢失。同时showMainContent初始值为字符串"",存在类型不一致问题。
修复:
- 将
showMainContent初始值设为true,保持布尔类型统一 - 移除
TextInput的onFocus和onBlur事件,通过typeData的内容控制搜索列表显示,而非依赖焦点状态
修改HomeScreen中的状态初始化和TextInput属性:
// 状态初始化 const [showMainContent, setShowMainContent] = useState(true); // TextInput移除焦点事件 <TextInput placeholder="search" onChangeText={(data) => typingData(data)} value={typeData} style={/* 原有样式 */} />
2. allMedicines类型不一致的潜在问题
在typingData函数中,输入长度为1时将allMedicines设为字符串"Type medicine name",但SearchList的FlatList需要数组类型数据,会导致渲染异常,间接影响父组件稳定性。
修复:
保持allMedicines的数组类型,单独处理空数据提示:
const typingData = (value) => { setTypeData(value); if (value.length > 1) { setAllMedicines( medicines.filter((medi) => medi.name.toLowerCase().includes(value.toLowerCase()) ) ); setShowMainContent(false); } else if (value.length === 1) { setAllMedicines([]); setShowMainContent(false); } else { setAllMedicines(medicines); setShowMainContent(true); } };
在SearchList中添加空数据提示:
const SearchList = ({ navigation, allMedicines }) => { if (!Array.isArray(allMedicines) || allMedicines.length === 0) { return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Text style={{ fontSize: 20, color: '#fff' }}>Type medicine name</Text> </View> ); } // 原有FlatList代码 };
3. 样式拼写错误修正
HomeContent中alignitems拼写错误,应为alignItems,修正后可保证图片居中显示:
<View style={{ flex: 2, alignSelf: "center", justifyContent: "center", alignItems: "center", // 修正拼写 paddingHorizontal: 5, }} >
4. 关闭按钮状态重置修复
closeSearchList中setAllMedicines("")会将数组改为字符串,修正为重置原始药品数组:
const closeSearchList = () => { Keyboard.dismiss(); console.log("close pressed"); setShowMainContent(true); setTypeData(""); setAllMedicines(medicines); // 重置为原始数组 };
内容的提问来源于stack exchange,提问作者reezal saini
相关产品推荐
相关产品推荐

