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

React StrictMode下Apollo Client错误致history.goBack()执行两次的解决办法

解决React StrictMode下Apollo Client错误触发两次history.goBack的问题

问题出在React StrictMode的开发环境特性:它会重复调用组件渲染和副作用逻辑,导致你在render回调里的history.goBack()执行了两次。以下是几种无需移除StrictMode的解决方案:

方案1:用useRef标记已处理的错误

通过ref变量记录是否已经处理过目标错误,避免重复执行跳转逻辑:

import { useRef } from 'react';
import { useHistory } from 'react-router-dom';
import { useSnackbar } from 'your-snackbar-package';

const Detail = () => {
  const { snackbar } = useSnackbar();
  const history = useHistory();
  // 标记是否已处理过该错误
  const errorHandled = useRef(false);

  return (
    <Compo query={graphQLQuery}>
      {({ data, error }) => {
        const hasSpecificError = error?.graphQLErrors[0]?.extensions?.debugMessage.includes('Specific Error');
        
        if (hasSpecificError) {
          // 仅在未处理过的情况下执行跳转和提示
          if (!errorHandled.current) {
            errorHandled.current = true;
            history.goBack();
            snackbar('Specific Error');
          }
          return <></>;
        } else {
          // 重置标记,确保后续错误能被正常处理
          errorHandled.current = false;
          // 渲染业务组件
          return <YourBusinessComponent data={data} />;
        }
      }}
    </Compo>
  );
};

方案2:用useEffect封装副作用逻辑

把跳转和提示逻辑放到useEffect中,利用依赖项控制触发时机,结合ref避免重复执行:

import { useRef, useEffect } from 'react';
import { useHistory } from 'react-router-dom';
import { useSnackbar } from 'your-snackbar-package';

const Detail = () => {
  const { snackbar } = useSnackbar();
  const history = useHistory();
  const errorHandled = useRef(false);

  return (
    <Compo query={graphQLQuery}>
      {({ data, error }) => {
        useEffect(() => {
          const hasSpecificError = error?.graphQLErrors[0]?.extensions?.debugMessage.includes('Specific Error');
          
          if (hasSpecificError && !errorHandled.current) {
            errorHandled.current = true;
            history.goBack();
            snackbar('Specific Error');
          }
          
          // 当error变化且不再是目标错误时,重置标记
          return () => {
            if (!hasSpecificError) {
              errorHandled.current = false;
            }
          };
        }, [error, history, snackbar]);

        if (error?.graphQLErrors[0]?.extensions?.debugMessage.includes('Specific Error')) {
          return <></>;
        } else {
          return <YourBusinessComponent data={data} />;
        }
      }}
    </Compo>
  );
};

方案3:全局错误链接处理(推荐)

将特定错误的处理逻辑移到Apollo Client的全局错误链接中,彻底避开组件render阶段的重复执行问题:

// 创建全局错误链接
import { ApolloLink } from '@apollo/client';
import { useHistory } from 'react-router-dom';
import { useSnackbar } from 'your-snackbar-package';

// 若在非组件环境中使用,可通过react-router的history实例或context获取history
const createErrorLink = (history, snackbar) => {
  return new ApolloLink((operation, forward) => {
    return forward(operation).map(response => {
      const hasSpecificError = response.errors?.some(
        err => err.extensions?.debugMessage.includes('Specific Error')
      );
      
      if (hasSpecificError) {
        history.goBack();
        snackbar('Specific Error');
      }
      
      return response;
    });
  });
};

// 在Apollo Client配置中引入该链接
const client = new ApolloClient({
  link: ApolloLink.from([
    createErrorLink(historyInstance, snackbarInstance),
    // 你的HTTP链接或其他链接
    httpLink
  ]),
  // 其他配置项
});

原理说明

  • React StrictMode在开发环境中会重复执行render回调和副作用,目的是帮助开发者发现潜在的副作用问题。
  • 方案1和2通过ref标记状态,确保同一错误只会触发一次跳转;方案3将逻辑移到Apollo的链路层,不在组件render阶段执行,从根源避免重复触发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 12:55:25