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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 04:07:03