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

React项目中如何在Material UI里正确使用useRef

问题根因

你的代码失效有两个核心原因:

  1. 错误的ref绑定方式:TextField是Material UI封装的上层组件,不是原生<input>DOM节点,直接给组件传ref拿到的是MUI组件实例,不存在.value属性,自然读不到输入值。
  2. 缺失依赖导入:代码中用到了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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 00:27:20