0

I've got a function that makes a call to my Node backend, and retrieves an array of objects. This function, named queryDatabase, listed below:

function queryDatabase(locationName, timeFrame) {
    const location = locationName.charAt(0).toUpperCase() + locationName.slice(1);
    return new Promise((resolve) => {
        Axios.get(`/api/measurements/${location}/${timeFrame}`)
            .then((resp) => {
                console.log('RESPONSE', resp);
                resolve(resp.data);
            });
    });
}

This function is called by yet another function, getAllGroupNames, that retrieves an object and gets all group names out of it. This function returns a promise, with an array of the list of group names that my front-end needs to render.

export default function (locationName) {
    const arrayOfGroupNames = [];
    return new Promise((resolve) => {
        queryDatabase('Pagodedreef', 'uur').then((data) => {
            data.forEach((measurement) => {
                measurement.groups.forEach((group) => {
                    if (!arrayOfGroupNames.includes(group.name)) {
                        arrayOfGroupNames.push(group.name);
                    }
                });
            });
            resolve(arrayOfGroupNames);
        });
    });
}

I feel the above code is correct. The problem, however, arises when a function in my front-end React code, calls getAllGroupNames and tries to iterate over the array to return a new Checkbox element for each value.

renderCheckboxes() {
    getAllGroupNames('Pagodedreef').then((array) => {
        return array.map((groupName, index) => (
            <div className="checkboxes" key={index.toString()}>
                <label htmlFor={groupName}>
                    <input
                        type="checkbox"
                        id={groupName}
                        value={groupName}
                        onChange={this.onCheckboxChange}
                        checked={this.props.selectedGroups.includes(groupName)}
                    />
                    {groupName}
                </label>
            </div>
        ));
    });
}

If I put a console.log() around the getAllGroupNames().then() function, it returns an unresolved promise. I can't figure out how I can, instead of returning a promise, return the elements that need to be rendered.

If I chain an additional .then() at the end of the previous then() and log the value of that - it lists the values that I do indeed need. But again, when I return those - it has no effect.

Thank you in advance for helping me.

Cake
  • 493
  • 7
  • 16
  • Avoid the [`Promise` constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it)! – Bergi Jan 30 '18 at 10:41
  • 1
    `I feel the above code is correct.` Your feelings are incorrect.. :) – Keith Jan 30 '18 at 10:42
  • A render method should never call a querydatabase method. – Bergi Jan 30 '18 at 10:42
  • "*how I can, instead of returning a promise, return the elements that need to be rendered.*" - you simply cannot. They'll only be available in the future. – Bergi Jan 30 '18 at 10:42

1 Answers1

1

Instead of creating a new Promise you can just return the result of db query. However, making a db call for a render method doesn't sound good for performance-wise point of view.

export default function (locationName) {
    return queryDatabase('Pagodedreef', 'uur').then((data) => {
        const arrayOfGroupNames = [];
        data.forEach((measurement) => {
            measurement.groups.forEach((group) => {
                if (!arrayOfGroupNames.includes(group.name)) {
                    arrayOfGroupNames.push(group.name);
                }
            });
        });
        return arrayOfGroupNames;
    });

}
Can
  • 599
  • 4
  • 13
  • Thank you for taking the time to reply. I rewrote the function as you described. However, inside the renderCheckboxes() method, the getAllGroupNames().then() still returns an unresolved promise. I don't quite understand how I need to rewrite that function to utilize the change we just made. – Cake Jan 30 '18 at 11:01
  • You have the same issue in db access function as well. Don't create promise while fetching data from db and return right after you recieve the data. – Can Jan 30 '18 at 11:05
  • Okay, I've removed the new Promise from queryDatabase, and instead returned the `resp.data` from the `.then()` method that is attached to `Axios.get()`. The problem I'm encountering is that when I put a `console.log()` around the Axios.get().then() method, it returns an unresolved promise, instead of the `resp.data`. – Cake Jan 30 '18 at 11:11
  • Once you are inside the promise chain, you will always get that. You can only access the result of promise inside a `then` method, not around it. – Can Jan 30 '18 at 11:13
  • Understood. That makes sense. But then how am I going to ensure my renderCheckboxes() gets the values (`divs`) that it needs? – Cake Jan 30 '18 at 11:15