无法访问componentDidMount中的状态 [英] cannot access state in componentDidMount

查看:65
本文介绍了无法访问componentDidMount中的状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am using library react-google-maps, and i want to use DirectionsRenderer between two nodes. Here is my state

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

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

I want to show the direction between my current location and marker. And my componentDidMount() is inside render method. Here is the code for render method

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;

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

when i use constant numbers in place of origin and destination it works fine.

推荐答案

首先,将组件 map 的名称更改为 Map .在此SO帖子上阅读 .

First things first, change the name of the component map to Map. Have a read at this SO post.

现在,关于这一点:

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

when i use constant numbers in place of origin and destination it works fine.

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

The answer to this question has a background, continue reading the following so that it is more clear.

上下文的问题

The problem of the this context

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

In your code, you have a map component, and you can access any of its properties (including the state) with this. If you call this.state inside the render function for example, you will get the state of map. You can use the componentDidMount function of the map component, to, for example, set a value in the state, like this:

class map extends Component {

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

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

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

This code will not fail, because componentDidMount is a React function for the component, and this can be used inside the component because it's in the same context. In this case, this.setState will set the state of map, because this is map.

这是您提供的示例的代码:

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 MapWithADirectionsRenderer .

In this example, this.setState refers to the context of MapWithADirectionsRenderer, so this.setState is setting the state of MapWithADirectionsRenderer, because this is MapWithADirectionsRenderer.

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

Now, in your code you are creating a new component called MyMapComponent as a const object. This component lets you define the componentDidMount function of that new component. That new component will have it's own context, so when you write this inside the MyMapComponent component, it will refer to MyMapComponent, not to map.

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

You cannot access the state of map from within MyMapComponent like that, you have to pass props to MyMapComponent.

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

I created a couple of examples on how to pass values.

解决方案1 ​​

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

You can create a prop with any name (in this example it's called test with the value 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>
));

通过这种方式,无论使用什么,都可以使用给定值记录 this.props.test .

This way, you can log this.props.test with the given value, whatever you use.

解决方案2

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

If what you need is to render the component depending on the value found in the state of Map, use something like this.

您可以将道具传递给 MyMapComponent ,然后使用 props.并添加道具的名称来访问它们.

You can pass props to MyMapComponent an then access them using props. and adding the name of the prop.

例如,如果您像这样传递名为 latProp 的新道具:

For example if you pass a new prop called latProp like this:

<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 中发送的值:

Since what you want is to replace the constant value with what you have in the state, just replace the values sent in props.latProp with whatever property you have in the state:

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

这是完整的组件:

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%` }} />,
  }),
  withScriptjs,
  withGoogleMap,
)(props => (
  <GoogleMap defaultZoom={8} defaultCenter={{ lat: -34.397, lng: 150.644 }}>
    {props.isMarkerShown && (
      <Marker position={{ lat: props.latProp, lng: props.lngProp }} />
    )}
  </GoogleMap>
));

class App extends Component{
  constructor(props){
    super(props);
    this.state = { lat: -34.400, lng: 151.644 }
  }
  render(){
    return (
      <div>
        <MyMapComponent isMarkerShown latProp={this.state.lat} lngProp={this.state.lng} />
      </div>
    );
  }
}
export default App;

这篇关于无法访问componentDidMount中的状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆