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

如何在按钮点击时用useMutation结果更新token?

解决React Query useMutation获取数据undefined问题及优化方案

先排查data undefined的核心原因

你的mutateAsync返回data为undefined,大概率是下面几个问题:

  • mutationFn未正确返回数据:如果只是发起请求但没return响应结果,自然拿不到数据;
  • 响应结构处理错误:比如用Axios时,后端返回的数据在response.data里,你直接return了response而非response.data;
  • 请求实际失败但未捕获:请求报错时mutateAsync会抛出异常,若没加try/catch,代码不会走到获取data的逻辑,容易误以为是data为undefined。

正确实现代码示例

1. 基础版:修正mutationFn并使用onSuccess处理逻辑

import { useMutation, useState } from '@tanstack/react-query';
import axios from 'axios';
import { useAuthContext } from './AuthContext';
import { useNavigate } from 'react-router-dom';

const LoginComponent = () => {
  const { setToken } = useAuthContext();
  const navigate = useNavigate();
  const [code, setCode] = useState('');
  const [login, setLogin] = useState('');

  const loginMutation = useMutation({
    // 核心:确保mutationFn返回后端的响应数据
    mutationFn: async ({ code, login }) => {
      const response = await axios.post('/api/login', { code, login });
      // 根据后端返回结构调整,比如直接返回response.data.token或整个数据对象
      return response.data;
    },
    // 成功回调:贴合React Query生命周期,统一处理后续逻辑
    onSuccess: (data) => {
      setToken(data.token);
      navigate('/profile');
    },
    // 错误处理:捕获请求失败场景
    onError: (error) => {
      console.error('登录失败:', error.response?.data?.message || error.message);
    }
  });

  const handleLogin = async () => {
    try {
      await loginMutation.mutateAsync({ code, login });
    } catch (error) {
      console.error('登录出错:', error);
    }
  };

  return (
    <div>
      <input value={code} onChange={(e) => setCode(e.target.value)} placeholder="Code" />
      <input value={login} onChange={(e) => setLogin(e.target.value)} placeholder="Login" />
      {/* 结合loading状态优化用户体验 */}
      <button onClick={handleLogin} disabled={loginMutation.isLoading}>
        {loginMutation.isLoading ? '登录中...' : '登录'}
      </button>
      {/* 显示错误提示 */}
      {loginMutation.isError && (
        <p style={{ color: 'red' }}>
          {loginMutation.error.response?.data?.message || '登录失败'}
        </p>
      )}
    </div>
  );
};

2. 优化版:抽离逻辑到自定义Hook和API层

第一步:抽离API请求逻辑(src/api/auth.js)

import axios from 'axios';

// 封装登录请求,统一处理响应结构
export const loginApi = async ({ code, login }) => {
  const response = await axios.post('/api/login', { code, login });
  return response.data;
};

第二步:创建自定义Hook(src/hooks/useLogin.js)

import { useMutation } from '@tanstack/react-query';
import { loginApi } from '../api/auth';
import { useAuthContext } from '../contexts/AuthContext';
import { useNavigate } from 'react-router-dom';

export const useLogin = () => {
  const { setToken } = useAuthContext();
  const navigate = useNavigate();

  return useMutation({
    mutationFn: loginApi,
    onSuccess: (data) => {
      setToken(data.token);
      navigate('/profile');
    },
    onError: (error) => {
      console.error('登录失败:', error.response?.data?.message || error.message);
      // 可集成全局错误提示组件,比如react-toastify
      // toast.error(error.response?.data?.message || '登录失败');
    }
  });
};

第三步:组件中使用自定义Hook

import { useState } from 'react';
import { useLogin } from './hooks/useLogin';

const LoginComponent = () => {
  const [code, setCode] = useState('');
  const [login, setLogin] = useState('');
  const loginMutation = useLogin();

  const handleLogin = () => {
    loginMutation.mutate({ code, login });
  };

  return (
    <div>
      <input value={code} onChange={(e) => setCode(e.target.value)} placeholder="Code" />
      <input value={login} onChange={(e) => setLogin(e.target.value)} placeholder="Login" />
      <button onClick={handleLogin} disabled={loginMutation.isLoading}>
        {loginMutation.isLoading ? '登录中...' : '登录'}
      </button>
      {loginMutation.isError && (
        <p style={{ color: 'red' }}>
          {loginMutation.error.response?.data?.message || '登录失败'}
        </p>
      )}
    </div>
  );
};

关键优化点说明

  1. 逻辑复用:将API请求和mutation逻辑抽离,多个组件需要登录功能时可直接复用useLogin Hook;
  2. 生命周期对齐:使用React Query的onSuccess/onError回调处理结果,而非在mutateAsync后手动处理,更贴合框架状态管理逻辑;
  3. 用户体验优化:结合isLoading/isError状态提供即时反馈,比如禁用按钮、显示加载提示和错误文本;
  4. 错误统一处理:集中捕获并处理请求错误,减少组件内冗余代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 20:53:20