0

I am having issues calling a function inside the map function in this React component.

This component should display a hierarchy of sorts in a table format. It should display a galaxys name and year discovered. Then it should iterate through and display all the known star systems in that galaxy, and finally, display each known planet in each of those star systems.

I've tried numerous suggestions that I've seen on SO and other websites.

When I do not use 'this' in front of the function, I get this error "populatePlanetData is not defined"

When I do use 'this', I get this error "this.populatePlanetData is not a function"

One of the answers I found suggested using an arrow function as suggested in this answer: "this" is undefined inside map function Reactjs

This one also suggests using arrow functions: Calling functions inside a map() function in React render()

But even with that arrow function, I still get the above errors. I can't figure out what I'm doing wrong. Is there anything obvious that's wrong or not done the correct way?

Here is the component:

import React, { Component } from 'react';

export class GetTestGalaxy extends Component {
static displayName = GetTestGalaxy.name;

constructor(props) {
    super(props);
    this.state = { galaxy: null, systems: [], planets: [], loading: true };
}

componentDidMount() {
    this.populateGalaxyData(482);
    this.populateSystemData(482);
}

static renderGalaxyTable(galaxy, systems, planets) {
    return (
        <table>
            <thead>
                <tr>
                    <th>Galaxy Name</th>
                    <th>Year</th>
                </tr>
            </thead>
            <tbody>
                <tr key={galaxy.id}>
                    <td>{galaxy.name}</td>
                    <td>{galaxy.year}</td>
                </tr>
                {this.systems.map(system =>
                    <tr>
                        <td>{system.name}</td>
                        <td>
                            {this.populatePlanetData(system.id).map(planet =>
                                    <span>{planet.name}</span>
                            )}
                        </td>
                    </tr>
                )}
            </tbody>
        </table>
    );
}

render() {
    let contents = this.state.loading
        ? <p><em>Loading...</em></p>
        : GetTestGalaxy.renderGalaxyTable(this.state.galaxy, this.state.systems, this.state.planets);

    return (
        <div>
            <h1 id="tabelLabel" >Galaxy Information</h1>
            {contents}
        </div>
    );
}

async populateGalaxyData(id) {
    const response = await fetch('https://localhost:44389/api/galaxylist/' + id);
    const data = await response.json();
    this.setState({ galaxy: data, loading: false });
}

async populateSystemData(id) {
    const response = await fetch('https://localhost:44389/api/systemlist/GetSystems/' + id);
    const data = await response.json();
    const result = Object.values(data);
    this.setState({ systems: result, loading: false });
}

async populatePlanetData(id) {
    const response = await fetch('https://localhost:44389/api/planetlist/GetPlanets/' + id);
    const data = await response.json();
    const result = Object.values(data);
    this.setState({ planets: result, loading: false });
}
}
6
  • 1
    er. async populatePlanetData(id) { -> async populatePlanetData = id => { won't do much, you are actually not returning anything from your async function. instead, it will set this.state.planets so you should loop that instead, just call the method.also, your method is 'static' so it's not bound to instance at all. remove 'static' declaration if you reference class variables Commented Nov 1, 2019 at 16:27
  • @DimitarChristoff Hi Dimitar, forgive my ignorance and thanks for the suggestion. I did put a console.write inside my async functions to make sure they are getting data back from the API, and they are. So I am still kind of lost. Commented Nov 1, 2019 at 16:37
  • 1
    If you are showing all galaxies and planets so you have to populate the state before render. So you should change populategalaxydata and populateplanetdata functions to store all information into state instead of fetching by id. You should also hold data in state as map so you can get required planet data with one touch Commented Nov 1, 2019 at 16:49
  • @mstfyldz, I kind of get what you are saying...I think. So would I add the map function to the async populategalaxydata and async populateplanetdata functions instead of doing it above? thanks! Commented Nov 1, 2019 at 16:52
  • 1
    static methods can't access this - then the rest of the refactor. your initial state will be an empty array but it will loop properly once the data arrives. Commented Nov 1, 2019 at 17:21

0

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.