0

I am rewriting some code to es6 syntax and i am having trouble. This is my first react native project so i am unfamiliar with some things. I am starting with this demo rn-background-geolocation-demo I added Navigation with a Login screen. When I login and switch views I am getting this error at

 onLayout() {
var me = this,
  gmap = this.refs.gmap;

this.refs.workspace.measure(function(ox, oy, width, height, px, py) {
  me.setState({
    mapHeight: height,
    mapWidth: width
  });
 });
}

undefined is not an object (evaluating 'this.refs')

here is the entire file. if u need more information let me know! thanks

Map.js

    class Map extends Component {
  constructor(props) {
    super(props)
    this.state = {
      locationIcon: require("image!green_circle"),
      currentLocation: undefined,
      locationManager: undefined,
      enabled: false,
      isMoving: false,
      odometer: 0,
      paceButtonStyle: commonStyles.disabledButton,
      paceButtonIcon: 'play',
      navigateButtonIcon: 'navigate',
      mapHeight: 300,
      mapWidth: 300,
      // mapbox
      center: {
        lat: 40.7223,
        lng: -73.9878
      },
      zoom: 10,
      markers: []
    }
  }

  componentDidMount() {

    var me = this,
      gmap = this.refs.gmap;

    this.locationManager = this.props.locationManager;

    // location event
    this.locationManager.on("location", function(location) {
      console.log('- location: ', JSON.stringify(location));
      me.setCenter(location);
      gmap.addMarker(me._createMarker(location));

      me.setState({
        odometer: (location.odometer / 1000).toFixed(1)
      });

      // Add a point to our tracking polyline
      if (me.polyline) {
        me.polyline.addPoint(location.coords.latitude, location.coords.longitude);
      }
    });
    // http event
    this.locationManager.on("http", function(response) {
      console.log('- http ' + response.status);
      console.log(response.responseText);
    });
    // geofence event
    this.locationManager.on("geofence", function(geofence) {
      console.log('- onGeofence: ', JSON.stringify(geofence));
    });
    // error event
    this.locationManager.on("error", function(error) {
      console.log('- ERROR: ', JSON.stringify(error));
    });
    // motionchange event
    this.locationManager.on("motionchange", function(event) {
      console.log("- motionchange", JSON.stringify(event));
      me.updatePaceButtonStyle();
    });

    // getGeofences
    this.locationManager.getGeofences(function(rs) {
      console.log('- getGeofences: ', JSON.stringify(rs));
    }, function(error) {
      console.log("- getGeofences ERROR", error);
    });

    SettingsService.getValues(function(values) {
      values.license = "eddbe81bbd86fa030ea466198e778ac78229454c31100295dae4bfc5c4d0f7e2";
      values.orderId = 1;
      values.stopTimeout = 0;
      //values.url = 'http://192.168.11.120:8080/locations';

      me.locationManager.configure(values, function(state) {
        console.log('- configure state: ', state);
        me.setState({
          enabled: state.enabled
        });
        if (state.enabled) {
          me.initializePolyline();
          me.updatePaceButtonStyle()
        }
      });
    });

    this.setState({
      enabled: false,
      isMoving: false
    });
  }
  _createMarker(location) {
    return {
      title: location.timestamp,
      id: location.uuid,
      icon: this.locationIcon,
      anchor: [0.5, 0.5],
      coordinates: {
        lat: location.coords.latitude,
        lng: location.coords.longitude
      }
    };
  }

  initializePolyline() {
    // Create our tracking Polyline
    var me = this;
    Polyline.create({
      points: [],
      geodesic: true,
      color: '#2677FF',
      width: 12
    }, function(polyline) {
      me.polyline = polyline;
    });
  }

  onClickMenu() {
    this.props.drawer.open();
  }

  onClickEnable() {
    var me = this;
    if (!this.state.enabled) {
      this.locationManager.start(function() {
        me.initializePolyline();
      });
    } else {
      this.locationManager.resetOdometer();
      this.locationManager.stop();
      this.setState({
        markers: [{}],
        odometer: 0
      });
      this.setState({
        markers: []
      });
      if (this.polyline) {
        this.polyline.remove(function(result) {
          me.polyline = undefined;
        });
      }
    }

    this.setState({
      enabled: !this.state.enabled
    });
    this.updatePaceButtonStyle();
  }

  onClickPace() {
    if (!this.state.enabled) {
      return;
    }
    var isMoving = !this.state.isMoving;
    this.locationManager.changePace(isMoving);

    this.setState({
      isMoving: isMoving
    });
    this.updatePaceButtonStyle();
  }

  onClickLocate() {
    var me = this;

    this.locationManager.getCurrentPosition({
      timeout: 30
    }, function(location) {
      me.setCenter(location);
      console.log('- current position: ', JSON.stringify(location));
    }, function(error) {
      console.error('ERROR: getCurrentPosition', error);
      me.setState({
        navigateButtonIcon: 'navigate'
      });
    });
  }

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

  setCenter(location) {
    this.setState({
      navigateButtonIcon: 'navigate',
      center: {
        lat: location.coords.latitude,
        lng: location.coords.longitude
      },
      zoom: 16
    });
  }

  onLayout() {
    var me = this,
      gmap = this.refs.gmap;

    this.refs.workspace.measure(function(ox, oy, width, height, px, py) {
      me.setState({
        mapHeight: height,
        mapWidth: width
      });
    });
  }

  updatePaceButtonStyle() {
    var style = commonStyles.disabledButton;
    if (this.state.enabled) {
      style = (this.state.isMoving) ? commonStyles.redButton : commonStyles.greenButton;
    }
    this.setState({
      paceButtonStyle: style,
      paceButtonIcon: (this.state.enabled && this.state.isMoving) ? 'pause' : 'play'
    });
  }

  render() {
    return (
      <View style={commonStyles.container}>
        <View style={commonStyles.topToolbar}>
          <Icon.Button name="android-options" onPress={this.onClickMenu} backgroundColor="transparent" size={30} color="#000" style={styles.btnMenu} underlayColor={"transparent"} />
          <Text style={commonStyles.toolbarTitle}>Background Geolocation</Text>
          <SwitchAndroid onValueChange={this.onClickEnable} value={this.state.enabled} />
        </View>
        <View ref="workspace" style={styles.workspace} onLayout={this.onLayout}>
          <RNGMap
            ref={'gmap'}
            style={{width: this.state.mapWidth, height: this.state.mapHeight}}
            markers={this.state.markers}
            zoomLevel={this.state.zoom}
            onMapChange={(e) => console.log(e)}
            onMapError={(e) => console.log('Map error --> ', e)}
            center={this.state.center} />

        </View>
        <View style={commonStyles.bottomToolbar}>
          <Icon.Button name={this.state.navigateButtonIcon} onPress={this.onClickLocate} size={25} color="#000" underlayColor="#ccc" backgroundColor="transparent" style={styles.btnNavigate} />
          <Text style={{fontWeight: 'bold', fontSize: 18, flex: 1, textAlign: 'center'}}>{this.state.odometer} km</Text>
          <Icon.Button name={this.state.paceButtonIcon} onPress={this.onClickPace} iconStyle={commonStyles.iconButton} style={this.state.paceButtonStyle}><Text>State</Text></Icon.Button>
          <Text>&nbsp;</Text>
        </View>
      </View>
    );
  }
};

module.exports = Map;

2 Answers 2

2

The problem comes from the line <View ref="workspace" style={styles.workspace} onLayout={this.onLayout}>; you're passing a reference to your onLayout function, but when it's called, it's called without a context. What you want to do is bind that function before passing the reference. There are many ways to do this, but the simplest is:

<View ref="workspace" style={styles.workspace} onLayout={this.onLayout.bind(this)}>
Sign up to request clarification or add additional context in comments.

Comments

0

Arrow Functions lexically bind "this", so if you write your onLayout() function like so:

onLayout = () => {
...
};

you will no longer need to bind it anywhere.

1 Comment

That would require the class properties proposal

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.