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 });
}
}
SkyeBoniwell
  • 6,345
  • 12
  • 81
  • 185
  • 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 – Dimitar Christoff Nov 01 '19 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. – SkyeBoniwell Nov 01 '19 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 – mstfyldz Nov 01 '19 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! – SkyeBoniwell Nov 01 '19 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. – Dimitar Christoff Nov 01 '19 at 17:21
  • @DimitarChristoff oh do you mean I need to remove the 'static' word? Thanks! – SkyeBoniwell Nov 01 '19 at 17:35

0 Answers0