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

React中TextField输入单个字符后失去焦点问题排查

React TextField输入单个字符后失焦的解决方案

问题原因

输入后立即失焦的核心问题是你在Text组件内部定义了Multiline、Password、TextInput这些子组件。每次父组件触发重渲染(比如onChange更新状态时),这些内部组件都会被重新创建,React会判定为全新组件,卸载旧实例并挂载新实例,导致焦点丢失。

修复方案

把内部子组件改为普通渲染函数,或者移到父组件外部,避免每次重渲染时重建组件类型:

修改后的完整代码

import * as React from "react";
import { styled } from "@mui/material/styles";
import Box from "@mui/material/Box";
import {
  TextField,
  Input,
  inputBaseClasses,
  FormControl,
  InputLabel
} from "@mui/material";
import { BiShow, BiHide } from "react-icons/bi";
import { useState } from "react";

const ValidationTextField = styled(TextField)({
  "& input:valid + fieldset": {
    borderColor: "green",
    borderWidth: 2
  },
  "& input:invalid + fieldset": {
    borderColor: "red",
    borderWidth: 2
  },
  "&:hover:valid + fieldset": {
    borderColor: "yellow"
  },
  "& input:valid:focus + fieldset": {
    borderLeftWidth: 6,
    borderColor: "purple",
    color: "pink",
    padding: "4px !important"
  },
  "& .MuiOutlinedInput-root": {
    "&:hover fieldset": {
      borderColor: "yellow",
      color: "orange"
    }
  }
});

const StyledInput = styled(Input)({
  borderRadius: 4,
  border: "2px solid blue",
  padding: 4,
  [`&.${inputBaseClasses.multiline}`]: {
    height: "auto",
    border: "2px solid red"
  }
});

// 移到外部作为独立组件,避免重复创建
const PassWordIcon = ({ showPass, setShowPass }) =>
  showPass ? (
    <BiHide size={40} onClick={() => setShowPass(false)} />
  ) : (
    <BiShow size={40} onClick={() => setShowPass(true)} />
  );

export default function Text({
  errors,
  label,
  rows,
  type,
  defaultValue,
  required,
  onChange,
  setValue,
  name
}) {
  const [showPass, setShowPass] = useState(false);

  // 改为普通渲染函数,而非React组件
  const renderMultiline = () => {
    return (
      <FormControl variant="outlined">
        <InputLabel>{label}</InputLabel>
        <StyledInput
          sx={{
            "&:hover": {
              border: "2px solid yellow"
            },
            "&.Mui-focused": {
              borderColor: "purple",
              color: "pink",
              padding: "4px !important"
            }
          }}
          onChange={(e) => onChange(e.target.value)}
          disableUnderline
          multiline
          rows={rows}
        />
      </FormControl>
    );
  };

  const renderPassword = () => {
    return (
      <Box>
        <ValidationTextField
          label={label}
          required={required}
          error={errors}
          onChange={(e) => onChange(e.target.value)}
          type={showPass ? "text" : "password"}
          sx={{
            input: {
              color: "red",
              "&::placeholder": {
                color: "darkgreen"
              }
            },
            label: {
              color: "pink"
            }
          }}
          variant="outlined"
          defaultValue={defaultValue}
        />
        <PassWordIcon showPass={showPass} setShowPass={setShowPass} />
      </Box>
    );
  };

  const renderTextInput = () => {
    return (
      <ValidationTextField
        label={label}
        required={required}
        type={type}
        onChange={(e) => onChange(e.target.value)}
        sx={{
          input: {
            color: "red",
            "&::placeholder": {
              color: "darkgreen"
            }
          },
          label: {
            color: "pink"
          }
        }}
        variant="outlined"
        defaultValue={defaultValue}
      />
    );
  };

  const inputType = (type) => {
    switch (type) {
      case "multiline":
        return renderMultiline();
      case "password":
        return renderPassword();
      default:
        return renderTextInput();
    }
  };

  return <Box>{inputType(type)}</Box>;
}

关键修改点

  1. 将PassWordIcon移到Text组件外部,作为独立组件复用,避免每次重渲染被重建
  2. 将原内部组件改为普通渲染函数(命名为renderXXX),不再以组件形式定义,确保每次重渲染时仅执行函数返回JSX,不创建新组件类型
  3. 移除了样式中无效的嵌套规则(比如&::placeholder内的&:hover fieldset,属于无效CSS嵌套)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 00:42:33