Javascript React组件内部的Async Meteor.call

Javascript React组件内部的Async Meteor.call,javascript,meteor,reactjs,Javascript,Meteor,Reactjs,我有一个React组件,其中包含一个GoogleMaps实例。我在基础设施中使用Meteor,问题是React组件是同步呈现的,但要获取服务器端变量,我必须求助于异步。如何妥善处理这种情况??以下是我的片段: import { Meteor } from 'meteor/meteor'; import React from 'react'; import { Gmaps, Marker, InfoWindow, Circle } from 'react-gmaps'; // Goals for

我有一个React组件,其中包含一个GoogleMaps实例。我在基础设施中使用Meteor,问题是React组件是同步呈现的,但要获取服务器端变量,我必须求助于异步。如何妥善处理这种情况??以下是我的片段:

import { Meteor } from 'meteor/meteor';
import React from 'react';
import { Gmaps, Marker, InfoWindow, Circle } from 'react-gmaps';

// Goals for this:
// - get the location of the user dynamically
// - see other users as markers

const coords = {
  lat: 51.5258541,
  lng: -0.08040660000006028,
};

export default class App extends React.Component {
  componentWillMount() {
    const params = {
      v: '3.exp',
      key: null,
    };

    Meteor.call('googleMapsApiKey', (err, res) => {
      if (!err) {
        params.key = res;
        console.log('params', params);
      }
    });
  }

  onMapCreated(map) {
    map.setOptions({
      disableDefaultUI: true,
    });
  }

  onDragEnd(e) {
    console.log('onDragEnd', e);
  }

  onCloseClick() {
    console.log('onCloseClick');
  }

  onClick(e) {
    console.log('onClick', e);
  }

  onDragStart(e) {
    console.log('onDragStart', e);
  }

  render() {
    return (
      <Gmaps
        width={'800px'}
        height={'600px'}
        lat={coords.lat}
        lng={coords.lng}
        zoom={12}
        loadingMessage={'Be happy'}
        params={params}
        onMapCreated={this.onMapCreated}
      >
        <Marker
          lat={coords.lat}
          lng={coords.lng}
          draggable
          onDragStart={this.onDragStart}
        />
        <InfoWindow
          lat={coords.lat}
          lng={coords.lng}
          content={'Hello, React :)'}
          onCloseClick={this.onCloseClick}
        />
        <Circle
          lat={coords.lat}
          lng={coords.lng}
          radius={500}
          onClick={this.onClick}
        />
      </Gmaps>
    );
  }
}
从'Meteor/Meteor'导入{Meteor};
从“React”导入React;
从“react Gmaps”导入{Gmaps,Marker,InfoWindow,Circle};
//这方面的目标:
//-动态获取用户的位置
//-将其他用户视为标记
常数坐标={
拉脱维亚:51.5258541,
液化天然气:-0.080406660000006028,
};
导出默认类App扩展React.Component{
组件willmount(){
常量参数={
v:'3.exp',
key:null,
};
Meteor.call('googleMapsApiKey',(呃,res)=>{
如果(!err){
params.key=res;
console.log('params',params);
}
});
}
onMapCreated(地图){
map.setOptions({
disableDefaultUI:true,
});
}
昂德拉根(e){
console.log('onDragEnd',e);
}
onCloseClick(){
log('onCloseClick');
}
onClick(e){
console.log('onClick',e);
}
昂德拉格起点(e){
console.log('onDragStart',e);
}
render(){
返回(
);
}
}
以下是显示同步/异步问题的指示控制台错误:


render方法似乎不会等待异步响应发生。解决这个问题的最佳实践是什么?

当您使用React.Component时,主要区别在于componentwillmount逻辑应该放在类构造函数中,如下所示:

从巴贝尔博客:

除了一个之外,所有的生命周期方法都可以按照您在使用新类语法时所期望的那样定义。类的构造函数现在承担以前由componentWillMount填充的角色:


设计React组件时,应考虑其可能具有的多种状态。例如,谷歌地图组件在显示地图之前必须加载,因此它有两种状态:加载和加载。这取决于流星呼叫的结果键:

export default class App extends React.Component {

  constructor(props) {
    super(props);

    this.state = {
      v: '3.exp',
      key: null
    };

    Meteor.call('googleMapsApiKey', (err, res) => {
      if (!err) {
        this.setState({ key: res })
      }
    });
  }

  ...

  render() {
    if (this.state.key) {
      return (
        <Gmaps
          width={'800px'}
          height={'600px'}
          lat={coords.lat}
          lng={coords.lng}
          zoom={12}
          loadingMessage={'Be happy'}
          params={this.state}
          onMapCreated={this.onMapCreated}
        >
          <Marker
            lat={coords.lat}
            lng={coords.lng}
            draggable
            onDragStart={this.onDragStart}
          />
          <InfoWindow
            lat={coords.lat}
            lng={coords.lng}
            content={'Hello, React :)'}
            onCloseClick={this.onCloseClick}
          />
          <Circle
            lat={coords.lat}
            lng={coords.lng}
            radius={500}
            onClick={this.onClick}
          />
        </Gmaps>
      );
    } else {
      return <div>Loading...</div>;
    }
  }
}
导出默认类App扩展React.Component{
建造师(道具){
超级(道具);
此.state={
v:'3.exp',
键:空
};
Meteor.call('googleMapsApiKey',(呃,res)=>{
如果(!err){
this.setState({key:res})
}
});
}
...
render(){
if(this.state.key){
返回(
);
}否则{
返回装载。。。;
}
}
}

基本上,我只是用一个状态替换了您的
常量参数
,并添加了一些加载管理。请注意,在ES6组件中,必须在构造函数中声明
此.state

异步工作应放在componentDidMount中。还有一种方法可以帮助您使用异步道具创建组件。 这就是一个例子

import { Meteor } from 'meteor/meteor';
import React from 'react';
import PropTypes from 'prop-types';
import { Gmaps, Marker, InfoWindow, Circle } from 'react-gmaps';
import { AsyncComponent } from 'react-async-wrapper';

// Goals for this:
// - get the location of the user dynamically
// - see other users as markers

const coords = {
  lat: 51.5258541,
  lng: -0.08040660000006028,
};

class App extends React.Component {

  onMapCreated(map) {
    map.setOptions({
      disableDefaultUI: true,
    });
  }

  onDragEnd(e) {
    console.log('onDragEnd', e);
  }

  onCloseClick() {
    console.log('onCloseClick');
  }

  onClick(e) {
    console.log('onClick', e);
  }

  onDragStart(e) {
    console.log('onDragStart', e);
  }

  render() {
    return (
      <Gmaps
        width={'800px'}
        height={'600px'}
        lat={coords.lat}
        lng={coords.lng}
        zoom={12}
        loadingMessage={'Be happy'}
        params={this.props.params}
        onMapCreated={this.onMapCreated}
      >
        <Marker
          lat={coords.lat}
          lng={coords.lng}
          draggable
          onDragStart={this.onDragStart}
        />
        <InfoWindow
          lat={coords.lat}
          lng={coords.lng}
          content={'Hello, React :)'}
          onCloseClick={this.onCloseClick}
        />
        <Circle
          lat={coords.lat}
          lng={coords.lng}
          radius={500}
          onClick={this.onClick}
        />
      </Gmaps>
    );
  }
}

App.propTypes = {
    params: PropTypes.object
}

App.defaultProps = {
    params: {
        v: '3.exp',
        key: null
    }
}

const AsyncApp = () => (
    <AsyncComponent asyncProps={{
        params: () => new Promise((resolve, reject) => {
            Meteor.call('googleMapsApiKey', (err, res) => {
                if (!err) {
                    resolve({
                        v: '3.exp',
                        key: res,
                    })
                } else {
                    reject(err)
                }
            });
        })
    }}
    >
        <App />
    </AsyncComponent>
)
从'Meteor/Meteor'导入{Meteor};
从“React”导入React;
从“道具类型”导入道具类型;
从“react Gmaps”导入{Gmaps,Marker,InfoWindow,Circle};
从“react async wrapper”导入{AsyncComponent};
//这方面的目标:
//-动态获取用户的位置
//-将其他用户视为标记
常数坐标={
拉脱维亚:51.5258541,
液化天然气:-0.080406660000006028,
};
类应用程序扩展了React.Component{
onMapCreated(地图){
map.setOptions({
disableDefaultUI:true,
});
}
昂德拉根(e){
console.log('onDragEnd',e);
}
onCloseClick(){
log('onCloseClick');
}
onClick(e){
console.log('onClick',e);
}
昂德拉格起点(e){
console.log('onDragStart',e);
}
render(){
返回(
);
}
}
App.propTypes={
参数:PropTypes.object
}
App.defaultProps={
参数:{
v:'3.exp',
键:空
}
}
常量AsyncApp=()=>(
新承诺((解决、拒绝)=>{
Meteor.call('googleMapsApiKey',(呃,res)=>{
如果(!err){
决心({
v:'3.exp',
键:res,
})
}否则{
拒绝(错误)
}
});
})
}}
>
)

您是否成功了?这感觉与答案很接近,但不幸的是Meteor在返回异步调用之前仍在渲染组件,这导致指示控制台发出“未找到api键”的警告。
import { Meteor } from 'meteor/meteor';
import React from 'react';
import PropTypes from 'prop-types';
import { Gmaps, Marker, InfoWindow, Circle } from 'react-gmaps';
import { AsyncComponent } from 'react-async-wrapper';

// Goals for this:
// - get the location of the user dynamically
// - see other users as markers

const coords = {
  lat: 51.5258541,
  lng: -0.08040660000006028,
};

class App extends React.Component {

  onMapCreated(map) {
    map.setOptions({
      disableDefaultUI: true,
    });
  }

  onDragEnd(e) {
    console.log('onDragEnd', e);
  }

  onCloseClick() {
    console.log('onCloseClick');
  }

  onClick(e) {
    console.log('onClick', e);
  }

  onDragStart(e) {
    console.log('onDragStart', e);
  }

  render() {
    return (
      <Gmaps
        width={'800px'}
        height={'600px'}
        lat={coords.lat}
        lng={coords.lng}
        zoom={12}
        loadingMessage={'Be happy'}
        params={this.props.params}
        onMapCreated={this.onMapCreated}
      >
        <Marker
          lat={coords.lat}
          lng={coords.lng}
          draggable
          onDragStart={this.onDragStart}
        />
        <InfoWindow
          lat={coords.lat}
          lng={coords.lng}
          content={'Hello, React :)'}
          onCloseClick={this.onCloseClick}
        />
        <Circle
          lat={coords.lat}
          lng={coords.lng}
          radius={500}
          onClick={this.onClick}
        />
      </Gmaps>
    );
  }
}

App.propTypes = {
    params: PropTypes.object
}

App.defaultProps = {
    params: {
        v: '3.exp',
        key: null
    }
}

const AsyncApp = () => (
    <AsyncComponent asyncProps={{
        params: () => new Promise((resolve, reject) => {
            Meteor.call('googleMapsApiKey', (err, res) => {
                if (!err) {
                    resolve({
                        v: '3.exp',
                        key: res,
                    })
                } else {
                    reject(err)
                }
            });
        })
    }}
    >
        <App />
    </AsyncComponent>
)