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

Apollo项目组件包裹顺序疑问:添加Mutation后出现Could not find 'client'错误求助

问题分析与解决方案

首先咱们直接戳中核心问题:你的ErrorBoundary现在是整个组件树的最外层,而ApolloProvider嵌套在它内部。当ErrorBoundary触发并渲染ErrorPrompt这个Fallback组件时,它其实处于ApolloProvider的上下文覆盖范围之外——这就是为什么明明加了ApolloProvider,却还是报找不到client的错误。

组件包裹顺序的关键影响

React上下文(Context)的作用逻辑是自上而下覆盖子组件树,只有在提供者组件(比如ApolloProvider、RecoilRoot)内部的子组件,才能访问到对应的上下文数据。所以包裹顺序直接决定了依赖上下文的库(比如Apollo)能否正常工作。

正确的包裹顺序调整方案

你需要把ErrorBoundary移动到所有上下文提供者的内部,确保它的Fallback组件能落在Apollo的上下文范围内。调整后的组件结构如下:

export default function App() {
  const ErrorPrompt = (props) => {
    useEffect(() => {
      sendErrorEmail({ variables: { errorCode: props.error.toString() } })
    }, [])
    return(
      // 原有的UI内容保持不变
      <View>
        <View style={{height: 50, width: '100%', backgroundColor: "#534FFF"}}/>
        <Text style={{...Template.title, fontSize: 30}}>Something happened!</Text>
        <Text style={{...Template.subTitle, fontSize: 20}}>We apologize for the inconvenience</Text>
        <Text style={{...Template.title, fontSize: 20, color: '#534FFF'}}>{props.error.toString()}</Text>
        <View style={{marginLeft: 30}}>
          <Text style={{...Template.subTitle, fontSize: 15, marginRight: 30, marginLeft: 0}}>An email has been sent to the Support Team to attempt to prevent this error from occurring again. We thank you for your support and patience</Text>
        </View>
        <View style={{marginTop: 50}}>
          <Button onPress={props.resetError} title={'Reload Application'} />
        </View>
      </View>
    )
  }

  if(!loaded){
    return null
  }
  try{
    return (
      <NavigationContainer>
        <ApolloProvider client={client}>
          <RecoilRoot>
            <IconRegistry icons={EvaIconsPack} />
            <ApplicationProvider {...eva} theme={{...eva.light, ...theme}}>
              <PaperProvider>
                <KeyboardAvoidingView behavior="padding" enabled style={{flexGrow:1,height:'110%'}} >
                  {/* 把ErrorBoundary移到这里,确保它在所有上下文提供者内部 */}
                  <ErrorBoundary FallbackComponent={ErrorPrompt} >
                    <View style={AppStyles.container}>
                      <Stack.Navigator screenOptions={{headerShown: false}}>
                        <Stack.Screen name="/">
                          {props => <LandingPage {...props} handleLoggedIn={handleLoggedIn} rememberMe={rememberMe} setRememberMe={setRememberMe} />}
                        </Stack.Screen>
                        <Stack.Screen name="home">
                          {props => <Home {...props} handleLoggedIn={handleLoggedIn} />}
                        </Stack.Screen>
                        {/* 其他Stack Screen保持不变 */}
                      </Stack.Navigator>
                    </View>
                  </ErrorBoundary>
                </KeyboardAvoidingView>
              </PaperProvider>
            </ApplicationProvider>
          </RecoilRoot>
        </ApolloProvider>
      </NavigationContainer>
    )
  } catch(error){
    // 额外处理:这里的ErrorPrompt同样不在上下文里,如果需要发送邮件,可手动传入client
    return(<ErrorPrompt error={error} />)
  }
}

补充优化建议

对于代码末尾catch块直接返回ErrorPrompt的场景,这个组件同样不在Apollo上下文范围内。如果这个场景也需要发送错误邮件,你可以二选一:

  • 把全局try/catch的逻辑整合到ErrorBoundary中,统一处理所有错误;
  • 在ErrorPrompt中手动传入client实例,比如:
    const [sendErrorEmail] = useMutation(SEND_ERROR_EMAIL_MUTATION, { client })
    

调整后,无论是ErrorBoundary触发的Fallback,还是其他需要使用Apollo的场景,都能正常获取到client上下文了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 00:52:44