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

React Native使用React-Query Mutation出现'Should have a queue'错误求助

React Native + React Query 登录Mutation触发时出现Hook调用顺序错误

我在React Native应用里用React Query的mutation实现Firebase登录,点击SignIn组件的提交按钮触发mutation,虽然mutation能执行到成功回调,但一直报错:"Error: Should have a queue. This is likely a bug in React. Please file an issue.",网上相关实现指引不多,求解决。


完整错误信息

Running "App" with {"rootTag":231,"initialProps":{}}
 ERROR  Warning: React has detected a change in the order of Hooks called by SignIn. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://react.dev/link/rules-of-hooks

   Previous render            Next render
   ------------------------------------------------------
1. useRef                     useRef
2. useState                   useRef
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    in SignIn (created by SignMain)
    in RCTView (created by View)
    in View (created by AnimatedComponent(View))
    in AnimatedComponent(View)
    in Unknown (created by SignMain)
    in RCTView (created by View)
    in View (created by AnimatedComponent(View))
    in AnimatedComponent(View)
    in Unknown (created by SignMain)
    in RCTView (created by View)
    in View (created by SignMain)
    in RCTView (created by View)
    in View (created by KeyboardAvoidingView)
    in RCTView (created by View)
    in View (created by KeyboardAvoidingView)
    in KeyboardAvoidingView (created by SignMain)
    in RCTScrollContentView (created by ScrollView)
    in RCTScrollView (created by ScrollView)
    in ScrollView (created by ScrollView)
    in ScrollView (created by SignMain)
    in SignMain (created by AuthNavigation)
    in AuthNavigation (created by App)
    in EnsureSingleNavigator
    in BaseNavigationContainer
    in ThemeProvider
    in NavigationContainerInner (created by App)
    in WithSplashScreen (created by App)
    in App (created by AppWrapper)
    in QueryClientProvider (created by AppWrapper)
    in AppWrapper
    in RCTView (created by View)
    in View (created by AppContainer)
    in RCTView (created by View)
    in View (created by AppContainer)
    in AppContainer
    in App(RootComponent)
 ERROR  Error: Should have a queue. This is likely a bug in React. Please file an issue.

This error is located at:
    in SignIn (created by SignMain)
    in RCTView (created by View)
    in View (created by AnimatedComponent(View))
    in AnimatedComponent(View)
    in Unknown (created by SignMain)
    in RCTView (created by View)
    in View (created by AnimatedComponent(View))
    in AnimatedComponent(View)
    in Unknown (created by SignMain)
    in RCTView (created by View)
    in View (created by SignMain)
    in RCTView (created by View)
    in View (created by KeyboardAvoidingView)
    in RCTView (created by View)
    in View (created by KeyboardAvoidingView)
    in KeyboardAvoidingView (created by SignMain)
    in RCTScrollContentView (created by ScrollView)
    in RCTScrollView (created by ScrollView)
    in ScrollView (created by ScrollView)
    in ScrollView (created by SignMain)
    in SignMain (created by AuthNavigation)
    in AuthNavigation (created by App)
    in EnsureSingleNavigator
    in BaseNavigationContainer
    in ThemeProvider
    in NavigationContainerInner (created by App)
    in WithSplashScreen (created by App)
    in App (created by AppWrapper)
    in QueryClientProvider (created by AppWrapper)
    in AppWrapper
    in RCTView (created by View)
    in View (created by AppContainer)
    in RCTView (created by View)
    in View (created by AppContainer)
    in AppContainer
    in App(RootComponent), js engine: hermes

相关代码

signIn.tsx

function SignIn() {

  const signInMutation = authAPI_login;
  const validationSchema = loginValidation;

  type SignInFormSchema = z.infer<typeof validationSchema>;

  const {control, handleSubmit, setFocus} = useForm<SignInFormSchema>({
    defaultValues: loginFormData,
    resolver: zodResolver(validationSchema),
  });

  const onSubmit = async (data: any) => {
     signInMutation.mutate({
          email: data.email,
          password: data.password,
        });
  };

  return (
    <View style={styles.rootContainer}>
      <View style={styles.inputContainer}>
        <TxtInput
          height={40}
          width={300}
          control={control}
          name="email"
          placeholder="Email"
          inputMode="email"
          nextFocus={true}
          isLoading={false}
          secureTextEntry={false}
          setNextFocus={() => {
            setFocus('password');
          }}
        />
      </View>
      <View style={styles.inputContainer}>
        <TxtInput
          height={40}
          width={300}
          control={control}
          name="password"
          placeholder="Password"
          inputMode="text"
          isLoading={false}
          secureTextEntry={true}
        />
      </View>
        <Button
          height={40}
          width={300}
          outline={true}
          isListening={true}
          isLoading={false}
          // onPress={handleSubmit(onSubmit)}
          onPress={() => {return onSubmit('test') }}
          >
          Sign In
        </Button>
     
    </View>
  );
}

api.tsx

export async function authSV_login(email: string, password: string) {
  return auth()
    .signInWithEmailAndPassword(email, password)
    .then((auth) => {
      return true
    })
    .catch(error => {
      if (error.code === 'auth/email-already-in-use') {
        console.log('That email address is already in use!');
      }

      if (error.code === 'auth/invalid-email') {
        console.log('That email address is invalid!');
      }

      return false
    });
}

export const authAPI_login = useMutation({
    mutationFn: ({ email, password }: {email: string, password: string}) => authSV_login(email, password),
    onSuccess: async (data) => {
      console.log('success', data);
    },
    onError: async (error) => {
      console.log('error', error);
    },
})

解决方案

核心问题

你在组件外部直接调用了useMutation Hook,违反了React Hook的核心规则:Hook必须在组件或自定义Hook的顶层调用,不能在组件渲染流程之外执行。这种写法会导致React无法跟踪Hook的调用顺序,进而触发Hook顺序错误警告,最终出现"Should have a queue"的报错。

修复步骤

  1. 将mutation改为自定义Hook
    修改api.tsx,把useMutation包裹在自定义Hook中,确保Hook在组件内部被调用:
export async function authSV_login(email: string, password: string) {
  return auth()
    .signInWithEmailAndPassword(email, password)
    .then((auth) => {
      return true
    })
    .catch(error => {
      if (error.code === 'auth/email-already-in-use') {
        console.log('That email address is already in use!');
      }

      if (error.code === 'auth/invalid-email') {
        console.log('That email address is invalid!');
      }

      return false
    });
}

// 改为自定义Hook
export const useAuthLoginMutation = () => {
  return useMutation({
    mutationFn: ({ email, password }: {email: string, password: string}) => authSV_login(email, password),
    onSuccess: async (data) => {
      console.log('success', data);
    },
    onError: async (error) => {
      console.log('error', error);
    },
  });
};
  1. 在SignIn组件内部调用自定义Hook
    修改signIn.tsx中的代码,替换原来的mutation引用:
function SignIn() {
  // 调用自定义Hook获取mutation
  const signInMutation = useAuthLoginMutation();
  const validationSchema = loginValidation;

  type SignInFormSchema = z.infer<typeof validationSchema>;

  const {control, handleSubmit, setFocus} = useForm<SignInFormSchema>({
    defaultValues: loginFormData,
    resolver: zodResolver(validationSchema),
  });

  const onSubmit = async (data: any) => {
     signInMutation.mutate({
          email: data.email,
          password: data.password,
        });
  };

  return (
    <View style={styles.rootContainer}>
      {/* 其余代码不变 */}
        <Button
          height={40}
          width={300}
          outline={true}
          isListening={true}
          isLoading={false}
          // 恢复使用handleSubmit传递正确的表单数据
          onPress={handleSubmit(onSubmit)}
          >
          Sign In
        </Button>
     
    </View>
  );
}
  1. 恢复表单数据传递
    把Button的onPress改回handleSubmit(onSubmit),确保表单的email和password能正确传递给mutation,避免测试代码导致的数据错误。

额外优化建议

可以修改authSV_login的错误处理逻辑,抛出明确的错误信息,方便在mutation的onError中捕获并提示用户:

export async function authSV_login(email: string, password: string) {
  try {
    await auth().signInWithEmailAndPassword(email, password);
    return true;
  } catch (error: any) {
    let errorMessage = '登录失败,请重试';
    switch(error.code) {
      case 'auth/invalid-email':
        errorMessage = '邮箱格式无效';
        break;
      case 'auth/user-not-found':
        errorMessage = '该账号不存在';
        break;
      case 'auth/wrong-password':
        errorMessage = '密码错误';
        break;
      case 'auth/too-many-requests':
        errorMessage = '请求过于频繁,请稍后再试';
        break;
    }
    throw new Error(errorMessage);
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 05:47:04