1

In my React Native application the class GeoService is a set of static methods with two declared static variables id and position.

If I try to reference the static class variable from its own static method with the this keyword, it seems to create a new variable in a different scope. Without this keyword it gives an outright error that the variable is unresolved.

Does the static keyword really mean anything useful in JS and what approach would work here to define static variables/methods?

CaptureView.js:

class CaptureView extends Component {
    constructor(props) {
        super(props);
        GeoService.start();
    }
    componentWillUnmount() {
        GeoService.stop();
    }
    onButtonPress() {
        Promise.all([this.cameraSrv.takePicture(), GeoService.getPosition()]).then(data => {
            let lat = data[1].lat; // PROBLEM HERE - Cannot read property 'lat' of undefined
            let log = data[1].lng;
        });
    }
}

GeoService.js:

import Logger from '../utils/Logger';

export default class GeoService {
    static _id = undefined;
    static _position = undefined;

    static start() {
        GeoService._getQuickPosition();
        GeoService._watchAccuratePosition();
    }

    static stop() {
        GeoService._clearWatch();
    }

    static getPosition() {
        return GeoService._position;
    }

    static _getQuickPosition() {
        navigator.geolocation.getCurrentPosition(
            GeoService._successCallback,
            GeoService._errorCallback,
            {enableHighAccuracy: false, timeout: 20000, maximumAge: 1000}
        );
    }

    static _watchAccuratePosition() {
        if (GeoService._id) {
            return;
        }

        GeoService._id = navigator.geolocation.watchPosition(
            GeoService._successCallback,
            GeoService._errorCallback,
            {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
        );
        Logger.info('GeoService watch started');
    }

    static _clearWatch() {
        navigator.geolocation.clearWatch(GeoService._id);
        delete GeoService._id;
        Logger.info('GeoService watch ended');
    }

    static _successCallback(position) {
        GeoService._position = {
            lat: position.coords.latitude,
            lng: position.coords.longitude
        };
        Logger.info('GeoService new position: ' + JSON.stringify(GeoService._position));
    }

    static _errorCallback(error) {
        Logger.info('GeoService error: ' + error);
    }
}

React Native console:

GeoService watch started
GeoService new position: {"lat":50.54822785298157,"lng":7.132454606843366}
GeoService new position: {"lat":50.54822785298157,"lng":7.132454606843366}
takePicture...
TypeError: Cannot read property 'lat' of undefined
    at CaptureView.js:187
    at tryCallOne (core.js:37)
    at core.js:123
    at JSTimers.js:298
    at _callTimer (JSTimers.js:152)
    at _callImmediatesPass (JSTimers.js:200)
    at Object.callImmediates (JSTimers.js:473)
    at MessageQueue.__callImmediates (MessageQueue.js:337)
    at MessageQueue.js:135
    at MessageQueue.__guard (MessageQueue.js:314)
3
  • Never write a class with only static methods! Commented Sep 4, 2019 at 15:17
  • The problem is that your getPosition() method simply returns undefined, whereas really it needs to return a promise for the data that is not yet avaiable. Commented Sep 4, 2019 at 15:20
  • @Bergi the class was just as an easy example. Commented Sep 4, 2019 at 15:20

2 Answers 2

1

Here is my solution, referring to static class variables as GeoService.xxx:

import Logger from '../utils/Logger';

export default class GeoService {
    static _id = undefined;
    static _position = undefined;

    static start() {
        GeoService._getQuickPosition();
        GeoService._watchAccuratePosition();
    }

    static stop() {
        GeoService._clearWatch();
    }

    static getPosition() {
        return GeoService._position;
    }

    static _getQuickPosition() {
        navigator.geolocation.getCurrentPosition(
            GeoService._successCallback,
            GeoService._errorCallback,
            {enableHighAccuracy: false, timeout: 20000, maximumAge: 1000}
        );
    }

    static _watchAccuratePosition() {
        if (GeoService._id) {
            return;
        }

        GeoService._id = navigator.geolocation.watchPosition(
            GeoService._successCallback,
            GeoService._errorCallback,
            {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
        );
        Logger.info('GeoService watch started');
    }

    static _clearWatch() {
        navigator.geolocation.clearWatch(GeoService._id);
        delete GeoService._id;
        Logger.info('GeoService watch ended');
    }

    static _successCallback(position) {
        GeoService._position = {
            lat: position.coords.latitude,
            lng: position.coords.longitude
        };
        Logger.info('GeoService new position: ' + JSON.stringify(GeoService._position));
    }

    static _errorCallback(error) {
        Logger.info('GeoService error: ' + error);
    }
}
Sign up to request clarification or add additional context in comments.

Comments

0

I think you can only use this inside an instance because it has to refer to an instanciated object. It looks like your solution is the proper way to write it.

I'm not sure, but inside your static class, I don't think you need to nest function calls like this:

    static getPosition() {
       return GeoService._position;
       // return _position; 
       // may work as well
    }

Comments

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.