无法访问componentDidMount

时间:2018-10-31 06:35:20

标签: reactjs google-maps render react-google-maps

我正在使用库react-google-maps,并且我想在两个节点之间使用DirectionsRenderer。 这是我的状态

this.state={
    currentPosition:{lat: 26.84 ,lng: 75.80},
    destinationPosition:{lat: 26.84 ,lng: 75.80},
};

我想显示当前位置和标记之间的方向。我的componentDidMount()在render方法中。 这是渲染方法的代码

class map extends React.PureComponent{
    constructor(props){
        super(props);
        this.state={
            currentPosition:{lat: 26.84 ,lng: 75.80},
            destinationPosition:{lat: 26.84 ,lng: 75.80},
            direction:false
        };
    }
    onMarkerPositionChanged(e){
        this.setState((state)=>({
            destinationPosition:{lat:e.latLng.lat(),lng:e.latLng.lng()}}));
    }
    handleClick(){
        if(navigator.geolocation){
            navigator.geolocation.getCurrentPosition((position)=>{
                this.setState(()=>({
                    currentPosition:{lat:position.coords.latitude,lng:position.coords.longitude}}))
            }); 
        }
        else{
            alert("Geoloaction is not supported by your browser");
        }
    }
    changeDir(){
        if(this.state.direction)
            this.setState(()=>({direction:false}))
        else
            this.setState(()=>({direction:true}))
    }
    render(){
        const MyMapComponent = compose(
          withProps({
            googleMapURL: "https://maps.googleapis.com/maps/api/js?key=AIzaSyC5VMMlyr_A6K5ycpOrq3OsVM8YYbn0q3A&v=3.exp&libraries=geometry,drawing,places",
            loadingElement: <div style={{ height: `100%` }} />,
            containerElement: <div style={{ height: `300px` }} />,
            mapElement: <div style={{ height: `100%` }} />,
          }),
          withScriptjs,
          withGoogleMap,
          lifecycle({       
            componentDidMount() {
                const google=window.google;
                console.log(this.state);
//--->this statement prints null
                const DirectionsService = new google.maps.DirectionsService();
                DirectionsService.route({
                origin: new google.maps.LatLng(this.state.currentPosition.lat, this.state.currentPosition.lng),
                destination: new google.maps.LatLng(this.state.destinationPosition.lat,this.state.destinationPosition.lng),
//---->  this is where i want to use the state to get the direction between //current location and marker
                travelMode: google.maps.TravelMode.DRIVING,
                }, (result, status) => {
                if (status === google.maps.DirectionsStatus.OK) {
                  this.setState({
                    directions: result,
                  });
                } else {
                  console.error(`error fetching directions ${result}`);
                }
              });
            }
          })
        )(
        props =>
          <GoogleMap defaultZoom={15} defaultCenter={this.state.destinationPosition} >
            <Marker position={this.state.destinationPosition} draggable changeLat
                onDragEnd={this.onMarkerPositionChanged.bind(this)}
            />
            <Marker
                icon="https://www.robotwoods.com/dev/misc/bluecircle.png"
                position={this.state.currentPosition}
            />
            {this.state.direction && props.directions && <DirectionsRenderer directions={props.directions} />}
            <Button bsStyle="success" onClick={this.handleClick.bind(this)}>Current Position</Button>
            <Button bsStyle="success" onClick={this.changeDir.bind(this)}>Get Direction</Button>
          </GoogleMap>
        );
        return(
            <Container state={this.state} map={MyMapComponent}/>
        );
    }
}
export default map;

当我使用常数代替起点和终点时,效果很好。

1 个答案:

答案 0 :(得分:0)

首先,将组件map的名称更改为Map。阅读at this SO post

现在,关于这一点:

  

当我使用常数代替起点和终点时,效果很好。

该问题的答案有一定的背景,请继续阅读以下内容,以使内容更加清楚。

this上下文问题

在代码中,您有一个map组件,您可以使用this访问其任何属性(包括状态)。例如,如果您在this.state函数内调用render,则会得到map的状态。您可以使用componentDidMount组件的map函数,例如,在状态中设置一个值,如下所示:

class map extends Component {

  constructor(props){
    this.state = { myVal: 1}
  }

  componentDidMount(){
    this.setState({ myVal: 2})
  }
}

该代码不会失败,因为componentDidMount是该组件的React函数,并且this可以在组件内部使用,因为它处于同一上下文中。在这种情况下,this.setState将设置map的状态,因为thismap

这是the example you provided的代码:

const { compose, withProps, lifecycle } = require("recompose"); const {   withScriptjs,   withGoogleMap,   GoogleMap,   DirectionsRenderer, } = require("react-google-maps");

const MapWithADirectionsRenderer = compose(   withProps({
    googleMapURL: "https://maps.googleapis.com/maps/api/js?key=AIzaSyC4R6AN7SmujjPUIGKdyao2Kqitzr1kiRg&v=3.exp&libraries=geometry,drawing,places",
    loadingElement: <div style={{ height: `100%` }} />,
    containerElement: <div style={{ height: `400px` }} />,
    mapElement: <div style={{ height: `100%` }} />,   }),   withScriptjs,   withGoogleMap,   lifecycle({
    componentDidMount() {
      const DirectionsService = new google.maps.DirectionsService();

      DirectionsService.route({
        origin: new google.maps.LatLng(41.8507300, -87.6512600),
        destination: new google.maps.LatLng(41.8525800, -87.6514100),
        travelMode: google.maps.TravelMode.DRIVING,
      }, (result, status) => {
        if (status === google.maps.DirectionsStatus.OK) {
          this.setState({
            directions: result,
          });
        } else {
          console.error(`error fetching directions ${result}`);
        }
      });
    }   }) )(props =>   <GoogleMap
    defaultZoom={7}
    defaultCenter={new google.maps.LatLng(41.8507300, -87.6512600)}
  >
    {props.directions && <DirectionsRenderer directions={props.directions} />}   </GoogleMap> );

<MapWithADirectionsRenderer />

在此示例中,this.setState指的是MapWithADirectionsRenderer的上下文,因此this.setState设置MapWithADirectionsRenderer的状态,因为this是{{1 }}。

现在,在您的代码中,您将创建一个名为MapWithADirectionsRenderer的新组件作为const对象。该组件使您可以定义该新组件的MyMapComponent函数。该新组件将具有自己的上下文,因此,当您在componentDidMount组件内编写this时,它将引用MyMapComponent,而不是MyMapComponent

您无法像这样从map内部访问map的状态,必须将道具传递给MyMapComponent

解决方案

我创建了一些有关如何传递值的示例。

解决方案1 ​​

您可以创建任何名称的道具(在本示例中,其值为MyMapComponent,称为test):

My value

通过这种方式,无论使用什么,都可以使用给定值记录const MyMapComponent = compose( withProps({ googleMapURL: "https://maps.googleapis.com/maps/api/js?key=AIzaSyC5VMMlyr_A6K5ycpOrq3OsVM8YYbn0q3A&v=3.exp&libraries=geometry,drawing,places", loadingElement: <div style={{ height: `100%` }} />, containerElement: <div style={{ height: `400px` }} />, mapElement: <div style={{ height: `100%` }} />, test:'My value' }), lifecycle({ componentDidMount() { console.log(JSON.stringify(this.props.test)); } }), withScriptjs, withGoogleMap, )(props => ( <GoogleMap defaultZoom={8} defaultCenter={{ lat: -34.397, lng: 150.644 }}> {props.isMarkerShown && ( <Marker position={{ lat: -34.397, lng: 150.644 }} /> )} </GoogleMap> ));

解决方案2

如果您需要根据在this.props.test状态下找到的值来渲染组件,请使用类似的东西。

您可以将道具传递到Map,然后使用MyMapComponent并添加道具名称来访问它们。

例如,如果您通过一个名为props.的新道具,如下所示:

latProp

您可以这样访问它:

<MyMapComponent isMarkerShown latProp={-34.397} />

由于您要用状态中的常量替换常数值,所以只需用状态中的任何属性替换(props => ( <GoogleMap defaultZoom={8} defaultCenter={{ lat: -34.397, lng: 150.644 }}> {props.isMarkerShown && ( <Marker position={{ lat: props.latProp, lng: 150.644 }} /> )} </GoogleMap> )); 中发送的值:

props.latProp

这是完整的组件:

<MyMapComponent isMarkerShown latProp={this.state.lat} />