使用FaEye/FaEyeSlash图标点击触发警告的React问题求助
密码显示/隐藏切换时React图标触发警告的解决方法
问题背景
在Login.jsx组件中使用FaEye和FaEyeSlash React图标实现密码显示/隐藏切换功能,但每次点击图标都会触发以下警告,切换为普通CSS替代TailwindCSS后问题依然存在。
相关代码
import { useContext, useState } from "react"; import { Link, Navigate } from "react-router-dom"; import axios from "axios"; import { FaEye, FaEyeSlash } from "react-icons/fa"; import { UserContext } from "../App"; function Login() { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [inputType, setInputType] = useState("password"); const [icon, setIcon] = useState(<FaEye />); const [success, setSuccess] = useState(""); const {state, dispatch} = useContext(UserContext); function handleToggle(e) { if (inputType === "password") { setInputType("text"); setIcon(FaEyeSlash); // 问题核心所在 } else { setInputType("password"); setIcon(FaEye); // 问题核心所在 } } function handleSubmit(e) { e.preventDefault(); const user = { email, password }; axios .post("http://localhost:5000/user/login", user) .then((res) =>{ dispatch({ type: "USER",payload: {name: res.data.user, logStatus: true, identity: res.data.identity}}); if ((res.data.identity.id === "Admin") && (res.data.identity.approved === false)){ setSuccess(`${res.data.user},please wait for the Admins to approve your account!`); }else{ setSuccess(`welcome ${res.data.user} you are successfully Logged in!`); } }) .catch((err) => { setSuccess("Incorrect password or email"); }); } if(state.logStatus){ return <Navigate to="/profile" state={{mes: success }} /> } return ( <form onSubmit={handleSubmit}> <div className="text-center text-lg text-red-500 font-semibold">{success}</div> <div className="h-auto w-5/12 border mx-auto rounded-2xl mt-3 "> <div className="h-2 bg-indigo-400 rounded-t-2xl mb-5 "></div> <div className="font-bold text-2xl text-center">Sign In</div> <div className="px-16"> <div className="mt-5 "> <label htmlFor="email" className="block font-semibold "> Email address </label> <input type="email" className="border h-5 w-full px-3 py-5 rounded-md focus:outline-2 focus:outline-blue-600" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Enter email" id="email" required /> </div> <div style={{position: 'relative'}}> <label htmlFor="pass" className="block font-semibold mt-5"> Password </label> <input type={inputType} className="border h-5 w-full px-3 py-5 rounded-md focus:outline-2 focus:outline-blue-600" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Enter password" id="pass" required /> <span style={{position: 'absolute', top:36, right:15}} onClick={handleToggle}> {icon} </span> </div> <div className=""> <button type="submit" className="mt-5 text-white bg-blue-600 border h-10 w-full py-2 rounded-md" > Submit </button> </div> <div className="flex justify-around"> <p className="mb-5 mt-3 text-left"> New here? <Link to="/sign-up" className="text-blue-600"> Register </Link> </p> <p className="mb-5 mt-3 text-right "> Forgot <Link to="/password-reset" className="text-blue-600"> password? </Link> </p> </div> </div> </div> </form> ); } export default Login;
警告信息
bundle.js:17688 Warning: Invalid values for props $$typeof, type on tag. Either remove them from the element, or pass a string or number value to keep them in the DOM. at svg at IconBase at span at div at div at div at form at Login at RenderedRoute at Routes at Routing at App at Router at BrowserRouter
问题原因
你在handleToggle函数中直接将图标组件(FaEyeSlash/FaEye)传递给setIcon,但初始状态中存储的是已经渲染好的JSX元素(<FaEye />)。当传递组件本身而非实例化的JSX时,React会尝试将组件的内部属性(如$$typeof、type)当作普通DOM属性渲染,从而触发警告。
修复方案
方案1:修正setIcon的参数
将setIcon(FaEyeSlash)改为setIcon(<FaEyeSlash />),setIcon(FaEye)改为setIcon(<FaEye />),确保每次存入状态的都是已实例化的JSX元素:
function handleToggle(e) { if (inputType === "password") { setInputType("text"); setIcon(<FaEyeSlash />); } else { setInputType("password"); setIcon(<FaEye />); } }
方案2:优化状态管理(更推荐)
不需要单独存储图标JSX,改用布尔状态变量控制显示逻辑,代码更简洁且避免状态存储JSX的潜在问题:
function Login() { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [showPassword, setShowPassword] = useState(false); // 用布尔状态替代图标JSX const [success, setSuccess] = useState(""); const {state, dispatch} = useContext(UserContext); function handleToggle(e) { setShowPassword(prev => !prev); // 切换布尔状态 } // 其余提交逻辑不变... return ( <form onSubmit={handleSubmit}> {/* 其余JSX不变... */} <div style={{position: 'relative'}}> <label htmlFor="pass" className="block font-semibold mt-5"> Password </label> <input type={showPassword ? "text" : "password"} // 根据状态切换输入框类型 className="border h-5 w-full px-3 py-5 rounded-md focus:outline-2 focus:outline-blue-600" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Enter password" id="pass" required /> <span style={{position: 'absolute', top:36, right:15}} onClick={handleToggle}> {showPassword ? <FaEyeSlash /> : <FaEye />} // 根据状态渲染对应图标 </span> </div> {/* 其余JSX不变... */} </form> ); }
两种方案都能解决警告问题,方案2的代码结构更清晰,也更符合React状态管理的最佳实践。
内容的提问来源于stack exchange,提问作者ayex
相关产品推荐
相关产品推荐

