React模态框表单集成授权时出现Invalid Hook call错误求助
解决React模态框表单授权中的Invalid Hook Call错误
问题描述
在模态框内的表单实现用户授权功能,UI功能正常,但添加useMutation授权逻辑后触发Invalid Hook call错误,已排除React版本不匹配问题。
相关代码
LoginModal组件
const LoginModal = (props) => { const [loginData, setLoginData] = useState({ email: "", password: "" }); const [validated] = useState(false); const [login, { error }] = useMutation(LOGIN_USER); const userInputHandler = (event) => { const { name, value } = event.target; setLoginData({ ...loginData, [name]: value }); }; const handleSubmit = async (event) => { event.preventDefault(); const form = event.currentTarget; if (form.checkValidity() === false) { event.preventDefault(); event.stopPropagation(); } try { const { data } = await login({ variables: { ...loginData }, }); Auth.login(data.login.token); } catch (err) { console.error(err); } setLoginData({ username: "", email: "", password: "", }); }; return ( <div> <div className="flex items-center justify-center md:z-100 min-h-screen bg-rose-50"> <form noValidate validated={validated} onSubmit={handleSubmit}> <div className="relative flex flex-col m-6 space-y-10 bg-white shadow-2xl rounded-2xl md:flex-row md:space-y-0 md:m-0"> {/* left side */} <div className="p-6 md-20"> {/* top content */} <h2 className="h2 mb-5 text-4xl font-bold cursor-pointer"> Login </h2> <p className="max-w-sm mb-12 font-light text-gray-600"> Login to see your saved activities! </p> <div className="space-y-4"> <input type="text" className="w-full space-y-4 p-6 border border-gray-300 rounded-md placeholder:font-light " placeholder="Email" onChange={userInputHandler} value={loginData.email} /> <input type="text" className="w-full space-y-4 p-6 border border-gray-300 rounded-md placeholder:font-light " placeholder="Password" onChange={userInputHandler} value={loginData.password} /> </div> {/* Middle Content */} <div className="flex flex-col items-center justify-between mt-6 space-y-6 md:flex-row md:space-y-0"> <div className="font-thin text-cyan-700 cursor-pointer" onClick={props.SwitchModal} > Sign Up </div> <button disabled={!loginData.email && loginData.password} className="w-full md:w-auto flex justify-center items-center p-6 space-x-4 font-bold text-white rounded-md px-9 bg-cyan-700 shadow-cyan-100 hover:bg-opacity-90 shadow-sm hover:shadow-lg border transition hover:-translate-y-0.5 duration-150 "> <span>Next</span> <FaHandPointRight /> </button> </div> {/* Border */} <div className="mt-12 border-b border-b-gray-300"> </div> {/* Bottom Content */} <p className="py-6 text-sm font-thin text-center text-gray-400"> You can also login with </p> <div className="flex flex-col space-x-0 space-y-6 md:flex-row md:space-x-4 md:space-y-0"> <button className="flex items-center justify-center py-2 space-x-3 border border-gray-300 rounded shadow-sm hover:bg-opacity-30 hover:shadow-lg hover:-translate-y-0.5 transition duration-150 md:w-1/2 "> <FaFacebook /> <span className="font-thin">Facebook</span> </button> <button className="flex items-center justify-center py-2 space-x-3 border border-gray-300 rounded shadow-sm hover:bg-opacity-30 hover:shadow-lg hover:-translate-y-0.5 transition duration-150 md:w-1/2 "> <FcGoogle /> <span className="font-thin">Google</span> </button> </div> </div> {/* right side */} <img src={Chairman} alt="" className="w-[430px] hidden md:block" /> {/* Close button */} <div className="group absolute -top-5 right-4 md:top-4 hover:cursor-pointer hover:-translate-y-0.5 transition duration-150"> <FaWindowClose onClick={props.onShowModal} className="group-hover:text-gray-600" /> </div> </div> </form> </div> </div> ); }; export default LoginModal;
Mutation定义
import { gql } from "@apollo/client"; export const LOGIN_USER = gql` mutation login($email: String!, $password: String!) { login(email: $email, password: $password) { token user { _id username } } } `; export const ADD_USER = gql` mutation addUser($username: String!, $email: String!, $password: String!) { addUser(username: $username, email: $email, password: $password) { token user { _id username email } } } `; export const SAVE_TASK = gql` mutation saveTask($input: SavedTaskInput) { saveTask(input: $input) { _id username email savedTasks { activity type participants price link key accessibility } } } `; export const REMOVE_TASK = gql` mutation removeTask($key: String!) { removeTask(key: $key) { _id username email savedTasks { activity type participants price link key accessibility } } } `;
控制台错误

解决方案
排除React版本问题后,按以下步骤排查修复:
- 确保组件以React方式渲染:检查父组件调用
LoginModal的方式,必须使用JSX语法<LoginModal SwitchModal={...} onShowModal={...} />,不能直接作为普通函数调用。 - 保持Hook在组件顶层:确认
useMutation没有放在条件判断、循环或嵌套函数内,你的代码当前已经符合要求,继续保持即可。 - 检查Apollo Provider包裹情况:
useMutation属于Apollo Client Hook,必须在ApolloProvider上下文内使用。确保应用根组件有如下结构:import { ApolloProvider, ApolloClient, InMemoryCache } from '@apollo/client'; const client = new ApolloClient({ uri: '你的GraphQL API地址', cache: new InMemoryCache(), }); function App() { return ( <ApolloProvider client={client}> {/* 包含LoginModal的应用组件 */} </ApolloProvider> ); } - 补充输入框name属性:
userInputHandler依赖name属性更新loginData,给输入框添加对应属性:<input type="email" name="email" ... /> <input type="password" name="password" ... /> - 修复按钮disabled逻辑:当前逻辑错误,改为
disabled={!loginData.email || !loginData.password},确保邮箱或密码为空时按钮禁用。
内容的提问来源于stack exchange,提问作者ChrisWill303
相关产品推荐
相关产品推荐

