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

使用RTK Query编写React登录表单时遇Hook规则错误求助

解决RTK Query登录表单的两个错误

错误1:在handleSubmit中调用Hook违反规则

原因:React Hooks必须在函数组件顶层或自定义Hook里调用,不能在事件处理函数内部执行。useAuthenticateUserQuery是RTK Query生成的Hook,放在handleSubmit里不符合调用规则。

解决:登录是用户主动触发的操作,应该用Mutation替代Query。Query适合依赖参数自动触发的数据查询,Mutation更适合主动发起的验证/修改类请求。

错误2:isFetching未定义

原因:原代码里isFetching只在handleSubmit内部临时定义,组件顶层的按钮无法访问;再加上Hook调用位置错误,导致该值根本无法正确获取。

解决:改用Mutation后,在组件顶层调用Mutation Hook,直接拿到isFetching状态,供整个组件使用。


修改后的UserAPI.js

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';

export const usersApi = createApi({
  reducerPath: 'usersApi',
  baseQuery: fetchBaseQuery({
    baseUrl: 'http://localhost:3005',
    prepareHeaders: (headers, { getState }) => {
      const token = getState().auth.token;
      if (token) {
        headers.set('authorization', `Bearer ${token}`);
      }
      return headers;
    },
  }),
  endpoints: (builder) => ({
    register: builder.mutation({
      query: (user) => ({
        url: '/users',
        method: 'POST',
        body: user,
      }),
    }),
    getUsers: builder.query({
      query: () => '/users',
    }),
    // 将query改为mutation,适配主动触发的登录场景
    authenticateUser: builder.mutation({
      query: (credentials) => ({
        url: '/users',
        method: 'GET',
        params: {
          email: credentials.email,
          password: credentials.password
        },
      }),
      transformResponse: (response, { arg: credentials }) => {
        const users = response?.users;
        const matchingUser = users?.find((u) => u.email === credentials.email && u.password === credentials.password);
        return matchingUser || null;
      },
    }),
  }),
});

// 导出对应的Mutation Hook
export const { useRegisterMutation, useGetUsersQuery, useAuthenticateUserMutation } = usersApi;

修改后的LoginForm.js

import { useState } from 'react';
import { useAuthenticateUserMutation } from '../store/apis/userApi';
import { useNavigate } from 'react-router-dom';

function LoginForm() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const navigate = useNavigate();

  // 在组件顶层调用Mutation Hook,拿到触发函数和状态
  const [authenticateUser, { isFetching }] = useAuthenticateUserMutation();

  const handleSubmit = async (e) => {
    e.preventDefault();
    // 调用mutation触发登录请求
    const result = await authenticateUser({ email, password });
    
    if (result.data) {
      // 登录成功跳转到 dashboard
      navigate('/dashboard');
    } else {
      // 登录失败提示
      alert('Invalid username or password');
    }
  };

  return (
    <form onSubmit={handleSubmit} className="max-w-sm mx-auto">
      <div className="mb-4">
        <label htmlFor="email" className="block text-gray-700 font-bold mb-2">
          Email
        </label>
        <input
          type="email"
          id="email"
          className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
        />
      </div>
      <div className="mb-6">
        <label htmlFor="password" className="block text-gray-700 font-bold mb-2">
          Password
        </label>
        <input
          type="password"
          id="password"
          className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
        />
      </div>
      <div className="flex items-center justify-between">
        <button
          type="submit"
          disabled={!email || !password || isFetching}
          className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
        >
          Login
        </button>
      </div>
    </form>
  );
}

export default LoginForm;

补充说明:

  • 改用Mutation后,请求由用户点击提交按钮主动触发,完全符合登录场景的交互逻辑
  • 组件顶层获取的isFetching可以直接控制按钮禁用状态,避免重复提交
  • 调用authenticateUser后返回的结果包含data和error,能更清晰地处理成功/失败分支

内容的提问来源于stack exchange,提问作者R9102

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 17:42:42