React中如何避免单按钮点击触发两个按钮的点击函数?
登录/注册切换按钮触发多个事件的解决方案
问题描述
实现登录/注册切换功能时,设置了两个按钮,但点击任意一个按钮都会执行切换模式的函数,一次点击触发了两个onClick事件,需要让每个按钮仅执行对应函数。
原始代码
import React, { useState } from "react"; import LockIcon from "@mui/icons-material/Lock"; import VisibilityIcon from "@mui/icons-material/Visibility"; import { GoogleLogin } from "@react-oauth/google"; import jwt_decode from "jwt-decode"; import { useDispatch } from "react-redux"; import { useNavigate } from "react-router-dom"; import "./authStyles.css"; import { signUp, signIn } from "../../action/auth/authAction"; const initialStateForm = { fName: "", lName: "", email: "", password: "", confirmPassword: "", }; const Auth = () => { const [showPassword, setShowPassword] = useState(true); const [isSignup, setIsSignup] = useState(false); const [formData, setFormData] = useState(initialStateForm); const dispatch = useDispatch(); const navigate = useNavigate(); const switchMode = () => { setIsSignup((prevIsSignup) => !prevIsSignup); setShowPassword(false); console.log("switchMode " + isSignup); }; const handleSubmit = (e) => { e.preventDefault(); console.log("handleSubmit " + isSignup); // if (isSignup) { // dispatch(signUp(formData)); // } else { // dispatch(signIn(formData)); // } }; const handleChnage = (e) => { e.preventDefault(); setFormData({ ...formData, [e.target.name]: e.target.value }); }; const handleShowPassword = () => { setShowPassword((prevShowPassword) => !prevShowPassword); }; const googleSuccess = async (res) => { const decodeUser = jwt_decode(res.credential); dispatch({ type: "AUTH", payload: decodeUser }); navigate("/"); }; const googleFailure = (error) => { console.log(error); console.log("Google sign in is unsuccessfull"); }; return ( <div> <div className="sign-form-container"> <LockIcon></LockIcon> <span>{isSignup ? `Sign Up` : `Sign In`}</span> {isSignup && ( <> <input type="text" id="fName" name="fName" placeholder="First Name" onChange={handleChnage} /> <input type="text" id="lName" name="lName" placeholder="Last Name" onChange={handleChnage} /> </> )} <input type="email" id="email" name="email" placeholder="Email" onChange={handleChnage} /> <input type={showPassword ? `password` : `text`} id="password" name="password" placeholder="Password" onChange={handleChnage} /> <VisibilityIcon onClick={handleShowPassword} /> {isSignup && ( <> <input type="password" id="confirmPassword" name="confirmPassword" placeholder="Confirm password" onChange={handleChnage} /> </> )} <GoogleLogin onSuccess={googleSuccess} onFailure={googleFailure} cookiePolicy="single_host_origin" ></GoogleLogin> <button type="button" onClick={handleSubmit}> //button 1 {isSignup ? `Sign Up` : `Sign In`} </button> <button type="button" onClick={switchMode}> // button 2 {isSignup ? "Already have an account ? Sign In" : "Don't have and account? Sign Up"} </button> </div> </div> ); }; export default Auth;
问题原因与修复方案
1. 核心问题:JSX标签内的注释格式错误
你在按钮标签内部使用了//button 1这类单行注释,JSX不支持这种写法,注释会被当作按钮的文本节点渲染,干扰了事件绑定的正常逻辑,导致点击时触发异常事件。
2. 其他需要修正的问题
- 函数名拼写错误:
handleChnage改为handleChange,避免后续调用出错。 - 冗余代码:
handleChange里的e.preventDefault()是多余的,onChange事件不需要阻止默认行为。 - 状态更新优化:更新
formData时使用函数式更新,确保获取最新状态值,避免闭包问题。
修复后的代码
import React, { useState } from "react"; import LockIcon from "@mui/icons-material/Lock"; import VisibilityIcon from "@mui/icons-material/Visibility"; import { GoogleLogin } from "@react-oauth/google"; import jwt_decode from "jwt-decode"; import { useDispatch } from "react-redux"; import { useNavigate } from "react-router-dom"; import "./authStyles.css"; import { signUp, signIn } from "../../action/auth/authAction"; const initialStateForm = { fName: "", lName: "", email: "", password: "", confirmPassword: "", }; const Auth = () => { const [showPassword, setShowPassword] = useState(true); const [isSignup, setIsSignup] = useState(false); const [formData, setFormData] = useState(initialStateForm); const dispatch = useDispatch(); const navigate = useNavigate(); const switchMode = () => { setIsSignup((prevIsSignup) => !prevIsSignup); setShowPassword(false); console.log("switchMode " + isSignup); }; const handleSubmit = (e) => { e.preventDefault(); console.log("handleSubmit " + isSignup); // if (isSignup) { // dispatch(signUp(formData)); // } else { // dispatch(signIn(formData)); // } }; const handleChange = (e) => { setFormData(prev => ({ ...prev, [e.target.name]: e.target.value })); }; const handleShowPassword = () => { setShowPassword((prevShowPassword) => !prevShowPassword); }; const googleSuccess = async (res) => { const decodeUser = jwt_decode(res.credential); dispatch({ type: "AUTH", payload: decodeUser }); navigate("/"); }; const googleFailure = (error) => { console.log(error); console.log("Google sign in is unsuccessfull"); }; return ( <div> <div className="sign-form-container"> <LockIcon></LockIcon> <span>{isSignup ? `Sign Up` : `Sign In`}</span> {isSignup && ( <> <input type="text" id="fName" name="fName" placeholder="First Name" onChange={handleChange} /> <input type="text" id="lName" name="lName" placeholder="Last Name" onChange={handleChange} /> </> )} <input type="email" id="email" name="email" placeholder="Email" onChange={handleChange} /> <input type={showPassword ? `password` : `text`} id="password" name="password" placeholder="Password" onChange={handleChange} /> <VisibilityIcon onClick={handleShowPassword} /> {isSignup && ( <> <input type="password" id="confirmPassword" name="confirmPassword" placeholder="Confirm password" onChange={handleChange} /> </> )} <GoogleLogin onSuccess={googleSuccess} onFailure={googleFailure} cookiePolicy="single_host_origin" ></GoogleLogin> {/* button 1 */} <button type="button" onClick={handleSubmit}> {isSignup ? `Sign Up` : `Sign In`} </button> {/* button 2 */} <button type="button" onClick={switchMode}> {isSignup ? "Already have an account ? Sign In" : "Don't have an account? Sign Up"} </button> </div> </div> ); }; export default Auth;
关键修复点说明
- 把按钮内的
//button 1注释移到标签外,改用JSX支持的{/* 注释内容 */}格式。 - 修正
handleChnage为handleChange,确保函数名正确。 - 移除
handleChange中的e.preventDefault(),因为onChange事件不需要阻止默认行为。 - 更新
setFormData为函数式写法,避免因闭包导致的状态更新不及时问题。
内容的提问来源于stack exchange,提问作者Lakshan
相关产品推荐
相关产品推荐

