Search code examples
javascriptreact-nativeoopstaticstatic-methods

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)

Solution

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