简体   繁体   中英

Reference error, says variable is not defined

So I have a function which reads from Firebase database and then creates an array of objects. I have defined variable key , but it is still unavailable.

var usersList = [];

const ref = firebase.database().ref()

function fetchUsers() {

    ref.child('users').once('value').then(snap => {
        var promises = [];

        snap.forEach(childSnap => {

            var key = childSnap.key

            promises.push
                (ref.child(`users/${key}/points`).once('value')
            );


        });

        return Promise.all(promises);

    }).then(function(snapshots) {
        return snapshots.map(snapper => {
        var points = snapper.val()
        return {uid: key, points: points};
        })
    }).then(function(usersList) {
        console.log(usersList)
    })

}

And this is the error I get...

(node:11724) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): ReferenceError: key is not defined

If i just do: key = childSnap.key , then every object's uid is the same.

key is only defined within the forEach callback. Naturally you cannot then reference it from within the second then callback. Moreover, which key would it be? For the first entry? The second? Third?

Instead, you need to return the key with the value:

function fetchUsers() {
    ref.child('users').once('value').then(snap => {
        var promises = [];
        snap.forEach(childSnap => {
            var key = childSnap.key;
            promises.push(
                ref.child(`users/${key}/points`).once('value').then(
                    snapper => ({key, snapper})    // **
                )
            );
        });

        return Promise.all(promises);
    }).then(function(snapshots) {
        return snapshots.map(({key, snapper}) => { // **
            var points = snapper.val();
            return {uid: key, points: points};
        });
    }).then(function(usersList) {
        console.log(usersList);
    });
}

On the first ** line above, we're transforming the result from once so it returns an object with both the key and "snapper".

On the second ** line, we're using destructured parameters to receive those objects as the distinct key and snapper parameters.


FWIW, if you want to aggressively use concise arrows:

function fetchUsers() {
    ref.child('users').once('value').then(snap =>
        Promise.all(snap.map(childSnap => {
            const key = childSnap.key;
            return ref.child(`users/${key}/points`)
                        .once('value')
                        .then(snapper => ({key, snapper}));
        }))
    ).then(snapshots =>
        snapshots.map(({key, snapper}) => ({uid: key, points: snapper.val()}))
    ).then(usersList => {
        console.log(usersList);
    });
}

Also note the use of map rather than declaring an array and pushing to it from a forEach callback. :-)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM