React Native中配置GraphQL查询报错,求解问题原因及非Apollo替代方案
首先来说你的Apollo Client错误问题,提示找不到client上下文,大概率是这几个地方出了问题:
一、排查Apollo Client配置错误
1. 确认ApolloProvider的正确导入
你代码里用到了<ApolloProvider>,但没展示导入语句,一定要确保是从**@apollo/client**包导入的——旧版的react-apollo包已经被废弃,和新版@apollo/client的API完全不兼容:
// 正确导入方式 import { ApolloProvider } from '@apollo/client';
如果之前是从其他地方导入的,替换成这个就能解决大部分上下文丢失的问题。
2. 验证Client实例的有效性
在makeApolloClient函数里加个日志,确认client是否正常创建:
const makeApolloClient = () => { const link = new HttpLink({ uri: `http://10.0.0.151:3000/api/v1/graphql` }); const cache = new InMemoryCache(); const client = new ApolloClient({ link, cache }); console.log('Created Apollo Client:', client); // 检查控制台是否有正常输出 return client; };
另外要确保你的手机/模拟器和后端服务在同一个局域网内:10.0.0.151是电脑的本地IP没问题,但如果是iOS模拟器,也可以直接用http://localhost:3000(iOS模拟器会自动把localhost映射到电脑);Android模拟器则需要用http://10.0.0.151或者http://10.0.2.2(Android模拟器的localhost映射地址)。
3. 检查组件包裹范围
你的结构是ApolloProvider包裹Redux的Provider,这个顺序没问题,但要确保SigninScreen完全处于ApolloProvider的覆盖范围内——比如它必须是Root组件内部的子组件,不能在导航栈或者其他跳出ApolloProvider的层级里。
二、无需Apollo的GraphQL查询方案
如果不想用Apollo Client,完全可以直接用原生fetch或者axios发送POST请求到GraphQL端点,因为GraphQL本质就是基于HTTP的API:
方案1:使用原生fetch
import { useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; const SigninScreen = ({ navigation, saveToken }) => { const token = useSelector((state) => state.session.token); const [users, setUsers] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const fetchAllUsers = async () => { setLoading(true); try { const response = await fetch('http://10.0.0.151:3000/api/v1/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json', // 如果后端需要认证,这里添加Authorization头 // 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ query: ` { getAllUsers { email } } `, // 如果是mutation操作,还需要传入variables字段 // variables: { userId: 123 } }), }); const result = await response.json(); if (result.errors) { throw new Error(result.errors.map(e => e.message).join(', ')); } setUsers(result.data.getAllUsers); } catch (err) { setError(err.message); } finally { setLoading(false); } }; useEffect(() => { fetchAllUsers(); }, []); console.log('Users:', users); console.log('Loading:', loading); console.log('Error:', error); // 你的渲染逻辑... };
方案2:使用axios
如果你习惯用axios,逻辑类似:
import axios from 'axios'; import { useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; const SigninScreen = ({ navigation, saveToken }) => { const token = useSelector((state) => state.session.token); const [users, setUsers] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const fetchAllUsers = async () => { setLoading(true); try { const response = await axios.post( 'http://10.0.0.151:3000/api/v1/graphql', { query: ` { getAllUsers { email } } `, }, { headers: { 'Content-Type': 'application/json', // 认证头按需添加 // 'Authorization': `Bearer ${token}` }, } ); const result = response.data; if (result.errors) { throw new Error(result.errors.map(e => e.message).join(', ')); } setUsers(result.data.getAllUsers); } catch (err) { setError(err.message); } finally { setLoading(false); } }; useEffect(() => { fetchAllUsers(); }, []); console.log('Users:', users); console.log('Loading:', loading); console.log('Error:', error); // 你的渲染逻辑... };
这种方式的好处是轻量,不需要引入Apollo的庞大依赖,但缺点是需要自己处理缓存、状态管理、错误处理等重复逻辑;Apollo的优势就是帮你封装了这些复杂细节,适合大型项目使用。
内容的提问来源于stack exchange,提问作者Yama

