React Native iOS端GraphQL useQuery/useMutation未传JWT请求头问题
问题原因分析
- Apollo Client context静态初始化问题:当前直接传递context对象的写法,会在组件挂载时创建一次对象并缓存。尽管Redux中jwt更新后组件会重新渲染,但iOS端可能因渲染时机或Apollo内部优化,导致useQuery/useMutation未重新识别context变化,仍使用初始的空header值。
- iOS异步渲染与状态同步差异:iOS端React Native的渲染调度逻辑和Android不同,可能在jwt刚从Redux更新后,组件还未完成重新渲染,useQuery就已发起请求,导致header未携带最新jwt。
- Apollo缓存策略影响:首次登录后,useQuery可能复用了未携带jwt的缓存请求,导致header缺失;重启APP后缓存清空,请求恢复正常。
排查与解决方法
方法1:将context改为动态函数(最有效)
Apollo支持将context设为函数,每次发起请求时都会重新执行该函数获取最新header,避免静态对象的缓存问题。
useMutation修改:
const { jwt, pushToken } = useSelector((state: RootState) => state.auth); const [updateUser, updateUserData] = useMutation(UPDATE_USER_MUTATION, { context: () => ({ headers: { cookie: `jwt=${jwt}`, authorization: jwt ? `Bearer ${jwt}` : '', }, }), });
useQuery修改:
const { jwt, user, pushToken } = useSelector((state: RootState) => state.auth); const { data: my_info, error: my_infoError, loading: my_infoLoading, refetch: my_infoRefetch, } = useQuery(GET_ME, { context: () => ({ headers: { cookie: `jwt=${jwt}`, authorization: jwt ? `Bearer ${jwt}` : '', }, }), });
方法2:全局配置Apollo Client请求头
将header逻辑移到Apollo Client的HttpLink中,每次请求都动态获取最新jwt,避免在组件层面重复配置:
import { createHttpLink } from '@apollo/client'; import AsyncStorage from '@react-native-async-storage/async-storage'; const httpLink = createHttpLink({ uri: '你的GraphQL接口地址', async headers() { const jwt = await AsyncStorage.getItem('jwt'); return { cookie: `jwt=${jwt}`, authorization: jwt ? `Bearer ${jwt}` : '', }; }, }); // 随后将httpLink传入ApolloClient的配置中
注意:登录成功后要将jwt存入AsyncStorage,确保全局能获取到最新值。
方法3:强制跳过初始无效请求
给useQuery添加skip选项,直到jwt存在时再发起请求,避免初始无jwt的请求:
const { jwt } = useSelector((state: RootState) => state.auth); const { data: my_info, refetch: my_infoRefetch, } = useQuery(GET_ME, { skip: !jwt, context: () => ({ headers: { cookie: `jwt=${jwt}`, authorization: jwt ? `Bearer ${jwt}` : '', }, }), }); // 可选:当jwt出现时自动触发请求 useEffect(() => { if (jwt) { my_infoRefetch(); } }, [jwt, my_infoRefetch]);
方法4:确认Redux状态更新的正确性
- 确保登录后更新jwt的Redux action是同步执行的,或异步action完成后再跳转页面。
- 使用
shallowEqual优化useSelector的依赖检测,确保jwt变化时组件能及时重新渲染:import { shallowEqual, useSelector } from 'react-redux'; const { jwt } = useSelector(state => state.auth, shallowEqual);
方法5:禁用Apollo缓存(临时排查用)
给useQuery设置fetchPolicy: 'network-only',强制每次请求都走网络,排除缓存影响:
useQuery(GET_ME, { fetchPolicy: 'network-only', context: () => ({ headers: { cookie: `jwt=${jwt}`, authorization: jwt ? `Bearer ${jwt}` : '', }, }), });
内容的提问来源于stack exchange,提问作者Md. Moniruzzaman
相关产品推荐
相关产品推荐

