React+GraphQL项目中ApolloClient报forward(...).subscribe不是函数错误
问题原因分析与解决方案
先帮你拆解下问题,核心是GraphQL查询语法错误+参数类型不匹配,导致Apollo客户端无法正确解析请求,进而抛出网络错误。
1. 核心错误点:GraphQL查询语法不正确
你报错的查询语句写法有问题:
{ query GetPoints(id: Int) { pointsGet(id: $id) { date, alcohol, exercise, diet, notes } } }
这里有两个关键问题:
- 外层多了一对冗余的大括号,带命名的GraphQL查询不需要额外包裹外层大括号
- 变量定义位置错误,应该在查询名称后的括号里声明
$id: Int!(如果id是必填项),而不是直接把类型写在参数位置
2. 次要错误点:参数类型不匹配
从this.props.match.params.id拿到的id是字符串类型,但你的GraphQL接口期望的是Int类型,直接传递会导致类型不匹配。
修复后的完整代码
async componentDidMount() { const id = this.props.match.params.id; if (id !== 'new') { // 把字符串id转为数字类型 const numericId = parseInt(id, 10); const authLink = setContext(async (_, {headers}) => { const token = await this.props.auth.getAccessToken(); return { headers: { ...headers, authorization: token ? `Bearer ${token}` : '' } } }); const client = new ApolloClient({ link: authLink.concat(httpLink), cache: new InMemoryCache() }); // 修正后的GraphQL查询 client.query({ query: gql` query GetPoints($id: Int!) { pointsGet(id: $id) { date, alcohol, exercise, diet, notes } } `, variables: {id: numericId} }) .then(result => { console.log(result); // 注意:这里要改成result.data.pointsGet,因为你的查询字段是pointsGet this.setState({points: result.data.pointsGet}); }); } else { console.log('new!'); } }
额外优化建议
每次在componentDidMount里创建新的ApolloClient实例不是最佳实践,建议全局创建一次客户端实例,通过ApolloProvider注入到应用中,组件直接复用:
// src/apollo/client.js import { ApolloClient } from 'apollo-client'; import { setContext } from 'apollo-link-context'; import { InMemoryCache } from 'apollo-cache-inmemory'; import { createHttpLink } from 'apollo-link-http'; const httpLink = createHttpLink({ uri: '/graphql' }); // 替换成你的GraphQL端点 const authLink = setContext(async (_, { headers }) => { const token = await auth.getAccessToken(); // 这里需要适配你的auth实例获取方式 return { headers: { ...headers, authorization: token ? `Bearer ${token}` : '' } }; }); export const client = new ApolloClient({ link: authLink.concat(httpLink), cache: new InMemoryCache() });
然后在入口文件注入:
import { ApolloProvider } from 'react-apollo'; import { client } from './apollo/client'; function App() { return ( <ApolloProvider client={client}> {/* 你的应用组件 */} </ApolloProvider> ); }
这样组件里就不用重复创建客户端,直接使用graphql高阶组件或useQuery钩子即可。
内容的提问来源于stack exchange,提问作者Matt Raible
相关产品推荐
相关产品推荐

