调用Apollo refetch()后组件props.data未重新加载的问题排查
解决Apollo Recompose模式下Refetch不更新组件的问题
看起来你在使用Apollo的Recompose模式处理错误和加载状态时,遇到了refetch后组件状态不更新的问题——ErrorScreen一直显示,LoadingScreen没出来,数据也没更新。我之前也踩过类似的坑,核心是几个关键点没处理到位,咱们一步步来解决:
问题根源
- Apollo没有通知组件状态变化:默认情况下,
graphql高阶组件不会在networkStatus变化时触发重渲染,而refetch时的加载状态是通过networkStatus(值为4,表示重新获取中)来体现的,不是loading(loading只对应首次查询)。 - 高阶组件没处理重新加载状态:你的
renderWhileLoading和renderIfError只判断了初始的loading和error,没考虑refetch过程中的networkStatus变化。 - 手动处理
refetch结果画蛇添足:你在handleRetry里手动then/catch了refetch的结果,但Apollo本来就会自动更新组件的dataprops,手动处理反而没意义,还可能掩盖了正常的更新流程。
具体修复步骤
1. 开启Apollo的网络状态通知
在你的withData配置里加上notifyOnNetworkStatusChange: true,这样组件会在networkStatus变化时重新渲染:
const options = { fetchPolicy: 'cache-and-network', notifyOnNetworkStatusChange: true // 关键:开启状态变化通知 }; const withData = graphql(userEvents, options);
2. 调整高阶组件,处理networkStatus
修改renderWhileLoading
让它同时识别首次加载的loading和refetch中的networkStatus === 4(Apollo定义的重新获取状态对应值为4):
// 更新renderWhileLoading的判断逻辑 export const renderWhileLoading = (LoadingComponent) => compose( branch( ({ data: { loading, networkStatus } }) => loading || networkStatus === 4, renderComponent(LoadingComponent) ) );
修改renderIfError
确保只有在存在错误且不在重新加载状态时,才显示ErrorScreen:
// 更新renderIfError的判断逻辑 export const renderIfError = (ErrorComponent) => compose( branch( ({ data: { error, networkStatus } }) => error && networkStatus !== 4, renderComponent(ErrorComponent) ) );
3. 简化ErrorScreen的refetch调用
删掉handleRetry里的.then和.catch,只需要调用refetch()就行——Apollo会自动处理数据更新和状态变化:
const ErrorScreen = ({ refetch, data }) => { const handleRetry = () => { refetch(); // 直接调用,不用手动处理结果 }; return ( <View style={styles.container}> <Text>{(data?.error?.message) || 'Something went wrong'}</Text> <Button title="Retry" onPress={handleRetry} /> </View> ); };
4. 确认setRefetchProp正确传递refetch
确保setRefetchProp把data.refetch传递给了子组件,比如:
export const setRefetchProp = () => withProps(({ data }) => ({ refetch: data.refetch }));
修复后的流程
现在当你点击Retry按钮后:
refetch()触发,Apollo把networkStatus设为4,组件重新渲染renderWhileLoading检测到networkStatus === 4,显示LoadingScreen,ErrorScreen隐藏- 如果
refetch成功:data更新,error消失,networkStatus回到正常状态,组件渲染原EventList - 如果
refetch失败:error保留,networkStatus回到非4状态,ErrorScreen重新显示
这样就完全符合你的预期结果了!
内容的提问来源于stack exchange,提问作者Chris Geirman
相关产品推荐
相关产品推荐

