React类组件使用Apollo查询GraphQL数据返回Promise问题求助
问题原因
client.query()本身返回的就是Promise实例,你直接将这个Promise赋值给data变量传递给App组件,拿到的自然不是实际的接口返回数据,和GraphQL的响应结构无关,属于异步调用的基础逻辑问题。你写的.then()链式调用只是定义了Promise的回调规则,不会同步返回异步结果。- 你尝试调用
.json()转换无效是因为Apollo Client已经自动完成了响应解析操作,json()是原生fetch接口的用法,不需要在Apollo的查询结果上调用。
类组件适配解决方案
因为项目要求使用类组件无法使用useQuery Hook,你可以选择以下两种方案实现:
方案1:类组件内部结合生命周期发起请求(更推荐)
在组件挂载后通过client发起查询,拿到结果后存入组件state触发渲染,不会阻塞首屏加载:
import React from 'react'; import { withApollo } from '@apollo/client'; // 高阶组件,自动注入client实例到props import { GET_DATA } from './gql定义文件的路径'; class App extends React.Component { state = { data: null, loading: true, error: null } componentDidMount() { // 从props拿到client实例发起请求 this.props.client.query({ query: GET_DATA }) .then(result => { this.setState({ data: result.data, loading: false }) }) .catch(err => { this.setState({ error: err, loading: false }) }) } render() { const { loading, error, data } = this.state; if (loading) return <div>数据加载中</div>; if (error) return <div>请求出错:{error.message}</div>; // 拿到数据后正常渲染业务逻辑 return ( <div> <h2>{data.category.name}</h2> {data.category.products.map(product => ( <div key={product.name}> <span>商品名:{product.name}</span> <span>库存状态:{product.inStock ? '有货' : '无货'}</span> </div> ))} </div> ) } } // 用withApollo包裹后组件props会自动获得client实例 export default withApollo(App);
对应的根渲染代码不需要提前请求,直接传递client即可:
ReactDOM.render( <ApolloProvider client={client}> <React.StrictMode> <App /> </React.StrictMode> </ApolloProvider>, document.getElementById("root") );
方案2:请求完成后再渲染根组件
如果你需要在应用渲染前就提前拿到所有数据,可以等Promise resolve之后再执行渲染逻辑:
// 提前发起请求,拿到结果后再渲染组件 client.query({ query: GET_DATA }) .then(result => { ReactDOM.render( <ApolloProvider client={client}> <React.StrictMode> <App data={result.data} /> </React.StrictMode> </ApolloProvider>, document.getElementById("root") ); }) .catch(err => { // 处理请求失败的兜底渲染 ReactDOM.render(<div>数据加载失败,请刷新页面重试</div>, document.getElementById("root")); })
注意:该方案会阻塞首屏渲染,直到接口请求完成才会显示页面内容,仅适合需要全局提前加载数据的场景。
内容的提问来源于stack exchange,提问作者Irakli Tchigladze
相关产品推荐
相关产品推荐

