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
相关产品推荐
相关产品推荐

