Apollo + React:数据未出现在 componentDidMount 生命周期中

Posted

技术标签:

【中文标题】Apollo + React:数据未出现在 componentDidMount 生命周期中【英文标题】:Apollo + React: data not appearing in componentDidMount lifecycle 【发布时间】:2018-06-17 16:58:34 【问题描述】:

我有一个 React 应用,它使用 Redux 进行一些应用内状态管理,并使用 Apollo 从服务器获取数据。在我的网络选项卡中,我的 graphql 查询成功并且响应是我所期望的,但是当我尝试在 React 组件的 componentDidMount 生命周期中引用数据时,数据不存在并且加载状态为“真”。

如果我将代码移动到不同的生命周期函数,例如 render(),数据确实会出现,但我需要它在 componentDidMount 中工作。我是阿波罗的新手。

import React,  Component  from "react";
import PropTypes from "prop-types";
import  connect  from "react-redux";

import SdkMap from "@boundlessgeo/sdk/components/map";
import SdkZoomControl from "@boundlessgeo/sdk/components/map/zoom-control";

import * as mapActions from "@boundlessgeo/sdk/actions/map";

import  graphql  from "react-apollo";
import gql from "graphql-tag";

function mapStateToProps(state) 
  return 
    map: state.map
  ;


class Map extends Component 
  static contextTypes = 
    store: PropTypes.object.isRequired
  ;

  componentDidMount() 
    const store = this.context.store;
    store.dispatch(mapActions.setView([-95.7129, 37.0902], 3));

    /* ADD SITES LAYER */
    store.dispatch(
      mapActions.addSource("sites_src", 
        type: "geojson",
        data: 
          type: "FeatureCollection",
          features: []
        
      )
    );

    store.dispatch(
      mapActions.addLayer(
        id: "sites",
        source: "sites_src",
        type: "circle",
        paint: 
          "circle-radius": 3,
          "circle-color": "blue",
          "circle-stroke-color": "white"
        
      )
    );
    
    console.log(this.props.data);  //response doesn't include query fields
    if (this.props.data.allSites) 
      let sites = this.props.data.allSites.edges;

      for (let i = 0; i < sites.length; i++) 
        let site = sites[i].node;
        let geojson = site.geojson;
        if (geojson) 
          console.log(site);
          const feature = 
            type: "Feature",
            geometry: geojson,
            properties: 
              id: site.id
            
          ;
          store.dispatch(mapActions.addFeatures("sites_src", feature));
        
      
    
  

  render() 
    const store = this.context.store;

    return (
      <SdkMap store=store >
        <SdkZoomControl />
      </SdkMap>
    );
  


const query = graphql(
  gql`
    query 
      allSites 
        edges 
          node 
            id
            projectId
            location
            areaAcres
            geojson
          
        
      
    
  `
);

const MapWithRedux = connect(mapStateToProps)(Map);
const MapWithApollo = query(MapWithRedux);

export default MapWithApollo;

【问题讨论】:

【参考方案1】:

首先不需要自己访问this.context。这是一种反模式。始终使用connect()。如果您需要组件中的部分状态,请使用mapStateToProps。如果您想从您的组件中调度操作,请使用mapDispatchToProps 将函数传递给它,为您执行调度。这是connect() 接受的第二个参数。

此外,没有理由将 store 传递给子组件,因为您可以单独连接需要 store 中任何内容的每个组件。

话虽如此,您的问题是获取数据是异步的,并且在调用 componentDidMount() 时您的请求可能未完成。所以loading 是真的信息只是意味着你的获取还没有完成。您可以通过例如向用户显示它显示某种微调器,或者在渲染组件之前获取所需的数据。

【讨论】:

谢谢,好的建议,我会做出这些改变。我只是遵循 Boundless SDK 的作者提供的 redux 模式,但看起来那里有一些改进。是的,显然异步获取在 componentDidMount() 被调用时还没有完成,但是如果我把从渲染方法中的 for 循环的东西,我得到一个无限循环的结果。 把它放在render() 方法中不是解决方案。获取数据需要不确定的时间,具体取决于您无法始终影响的外部因素。您需要显示一些内容,表明您的组件仍在加载初始数据,只要它仍在获取。一旦数据到达,您的组件将使用数据重新渲染。或者您可以自己提供初始数据并将它们作为初始状态存储在您的 redux 存储中。 还使用react-apollo 阅读prefetching 数据。这可能就是你想要的。 感谢您尝试引导我完成此操作,但我仍然缺少一些东西。在 componentDidMount() 中,如果我使用 console.log(this.props.data.loading),我会得到“真”。尽管在那个生命周期方法中什么都不会再发生,那么我如何订阅才能知道它何时为“假”? @bantingGamer 我对您的用例一无所知。在大多数情况下,您应该使用Query component 来获取数据,如果您熟悉 React 钩子,则应使用 useQuery

以上是关于Apollo + React:数据未出现在 componentDidMount 生命周期中的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 React 中的 Apollo 客户端中显示错误未显示

在 Apollo 客户端中使用 react-router 返回时 React 未更新其状态

React + Apollo:GraphQL 错误数组未传递到组件中

`data` 在 apollo useMutation Promise 中未定义

未捕获的错误:react-apollo 仅支持每个 HOC 的查询、订阅或突变

阿波罗突变未出现在道具中