React项目中如何在Material UI里正确使用useRef
问题根因
你的代码失效有两个核心原因:
- 错误的ref绑定方式:
TextField是Material UI封装的上层组件,不是原生<input>DOM节点,直接给组件传ref拿到的是MUI组件实例,不存在.value属性,自然读不到输入值。 - 缺失依赖导入:代码中用到了
InputAdornment组件但没有引入,运行时会直接抛出组件未定义的错误。
额外注意,你当前的表单没有配置type="submit"的触发按钮,就算ref问题修复也没法正常触发提交逻辑;密码输入框也没加type="password",输入内容会明文展示。
Material UI 中 useRef 绑定输入框的正确写法
MUI的TextField专门提供了inputRef属性,这个属性会把ref直接绑定到组件内部的原生input元素上,绑定后和你之前用原生input的ref逻辑完全一致,可以直接通过ref.current.value拿到输入值,是官方推荐的最简写法。
不需要额外做forwardRef转发之类的复杂处理,日常开发直接用inputRef替代普通ref即可。
修正后的可运行代码
import { useContext, useRef, useState } from "react"; import { Context } from "../../context/Context"; import axios from "axios"; import TextField from '@mui/material/TextField'; import Box from '@mui/material/Box'; import InputAdornment from '@mui/material/InputAdornment'; import EmailIcon from '@mui/icons-material/Email'; import LockIcon from '@mui/icons-material/Lock'; export default function Login() { const userRef = useRef(); const passwordRef = useRef(); const { dispatch, isFetching } = useContext(Context); const [error, setError] = useState(false); const handleSubmit = async (e) => { e.preventDefault(); dispatch({ type: "LOGIN_START" }); try { const res = await axios.post("/auth/login", { username: userRef.current.value, password: passwordRef.current.value, }); dispatch({ type: "LOGIN_SUCCESS", payload: res.data }); } catch (err) { dispatch({ type: "LOGIN_FAILURE" }); setError(true) } }; return ( <div className="login"> <form className="loginForm" onSubmit={handleSubmit}> <Box sx={{ display: "flex", flexDirection: "column", gap: 2, padding: 2 }}> <TextField type="email" required id="login-email" label="邮箱" variant="outlined" inputRef={userRef} InputProps={{ startAdornment: ( <InputAdornment position="start"> <EmailIcon /> </InputAdornment> ), }} /> <TextField type="password" id="login-password" label="密码" variant="outlined" inputRef={passwordRef} InputProps={{ startAdornment: ( <InputAdornment position="start"> <LockIcon /> </InputAdornment> ), }} /> <button type="submit" disabled={isFetching} style={{ padding: "10px", border: "none", borderRadius: "4px", cursor: "pointer" }} > {isFetching ? "登录中..." : "登录"} </button> {error && <span style={{color: "#d32f2f"}}>账号或密码错误,请重试</span>} </Box> </form> </div> ) }
关键修改点说明
- 把原来绑定在
TextField上的ref替换为inputRef,确保能拿到原生input元素 - 补充了缺失的
InputAdornment组件导入 - 给密码输入框添加
type="password"属性,隐藏输入内容 - 给两个输入框设置了不同的id,避免id重复导致的标签关联问题
- 添加了带
type="submit"的登录按钮,保证表单提交逻辑能正常触发 - 增加了登录中禁用按钮、错误提示的基础交互
内容的提问来源于stack exchange,提问作者sultan.h
相关产品推荐
相关产品推荐

