Peter G.
Peter G.

Reputation: 8054

Referencing static variables in JavaScript classes

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)

Upvotes: 1

Views: 525

Answers (2)

Kevin Subrebost
Kevin Subrebost

Reputation: 51

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
    }

Upvotes: 0

Peter G.
Peter G.

Reputation: 8054

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);
    }
}

Upvotes: 1

Related Questions