Material UI TextField输入中断问题排查求助
问题:Material UI TextField输入字符后失去焦点,需重新点击才能继续输入
问题描述
使用Material UI的TextField组件时,每次输入一个字符后就无法继续输入,必须重新点击输入框才能继续;移除onChange方法后,输入可正常连续进行,怀疑是组件渲染逻辑或useEffect导致问题。
相关代码
DataGridCustomToolbar组件
import React from "react"; import { Search } from "@mui/icons-material"; import { IconButton, TextField, InputAdornment } from "@mui/material"; import { GridToolbarDensitySelector, GridToolbarContainer, GridToolbarExport, GridToolbarColumnsButton, } from "@mui/x-data-grid"; import FlexBetween from "./FlexBetween"; const DataGridCustomToolbar = ({ searchInput, setSearchInput, setSearch }) => { return ( <GridToolbarContainer> <FlexBetween width="100%"> <FlexBetween> <GridToolbarColumnsButton /> {/* <GridToolbarDensitySelector /> */} <GridToolbarExport /> </FlexBetween> <TextField label="Search..." sx={{ mb: "0.5rem", width: "15rem" }} onChange={(e) => setSearchInput(e.target.value)} value={searchInput} variant="standard" InputProps={{ endAdornment: ( <InputAdornment position="end"> <IconButton onClick={() => { setSearch({ value: searchInput }); setSearchInput(""); }} > <Search /> </IconButton> </InputAdornment> ), }} /> </FlexBetween> </GridToolbarContainer> ); }; export default DataGridCustomToolbar;
BOM组件(DataGrid使用处)
import React, { useState, useEffect, useTheme } from "react"; import { Box } from "@mui/material"; import { StripedDataGrid } from "你的组件路径"; // 替换为实际组件路径 import dataService from "你的服务路径"; // 替换为实际服务路径 const BOM = () => { const theme = useTheme(); // 向后端传递的参数 const [page, setPage] = useState(0); const [limit, setlimit] = useState(20); const [order, setOrder] = useState([ { column: "1", dir: "asc", }, ]); const [search, setSearch] = useState({ value: "", }); const [data, setData] = useState([]); const [total, setTotal] = useState(0); const [searchInput, setSearchInput] = useState(""); useEffect(() => { dataService.getBomList(page, limit, order, search).then((response) => { console.log("BOM"); setData(response.data.data.data); setTotal(response.data.data.recordsFiltered); }); }, [page, limit, order]); const columns = [ { field: "sku", headerName: "SKU", width: 100, }, { field: "sku_name", headerName: "SKU NAME", width: 300 }, { field: "plant", headerName: "Plant", width: 80, align: "center", headerAlign: "center", }, { field: "base_qty", headerName: "Base QTY", width: 100 }, { field: "item", headerName: "Item", width: 60, align: "center", headerAlign: "center", }, { field: "uom_sku", headerName: "UOM SKU", width: 100, align: "center" }, { field: "material", headerName: "Material", width: 150 }, { field: "material_name", headerName: "Material Name", width: 300 }, { field: "qty_material", headerName: "Material QTY", width: 100 }, { field: "uom_material", headerName: "Material UOM", width: 100 }, { field: "alt_bom", headerName: "BOM ALT", width: 80 }, { field: "valid_from", headerName: "Valid From", width: 210 }, { field: "valid_to", headerName: "Valid to", width: 210 }, { field: "status", headerName: "Status", width: 80 }, ]; return ( <Box m="5px"> <Box height="80vh"> <StripedDataGrid getRowId={(row) => row.id} columns={columns} rowCount={(limit && total) || 0} rowsPerPageOptions={[20, 50, 100]} rows={data || []} pagination paginationMode="server" sortingMode="server" page={page} pageSize={limit} onPageSizeChange={(newPageSize) => setlimit(newPageSize)} onPageChange={(newPage) => setPage(newPage)} onSortModelChange={(newSortModel) => setOrder(...newSortModel)} components={{ Toolbar: DataGridCustomToolbar }} componentsProps={{ toolbar: { searchInput, setSearchInput, setSearch }, }} /> </Box> </Box> ); }; export default BOM;
错误原因及解决方案
核心错误点
onSortModelChange写法错误:原代码使用setOrder(...newSortModel)将排序数组展开为单个对象,导致order从数组变为对象,触发useEffect频繁执行、组件反复渲染,最终使TextField失去焦点。componentsProps.toolbar频繁生成新对象:每次searchInput变化时,BOM组件重新渲染,componentsProps.toolbar会生成新的对象引用,导致DataGrid重新挂载Toolbar组件,TextField被销毁重建,失去焦点。- 无用递归函数
setDataInput:该函数会无限递归调用自身,虽未被使用,但存在潜在崩溃风险。 useEffect依赖缺失:未将search加入依赖数组,导致搜索参数变化时无法触发后端数据请求。
修复步骤
- 修正排序逻辑:直接将排序数组赋值给
order:onSortModelChange={(newSortModel) => setOrder(newSortModel)} - 缓存Toolbar props:使用
useMemo缓存props对象,避免频繁创建新引用:import React, { useState, useEffect, useTheme, useMemo } from "react"; // ... componentsProps={{ toolbar: useMemo(() => ({ searchInput, setSearchInput, setSearch }), [searchInput, setSearchInput, setSearch]) }} - 删除无用递归函数:移除
setDataInput函数,消除潜在错误。 - 补充useEffect依赖:将
search加入依赖数组,确保搜索参数变化时重新请求数据:useEffect(() => { dataService.getBomList(page, limit, order, search).then((response) => { console.log("BOM"); setData(response.data.data.data); setTotal(response.data.data.recordsFiltered); }); }, [page, limit, order, search]);
内容的提问来源于stack exchange,提问作者JS24
相关产品推荐
相关产品推荐

