2

Confused as to why this Array (?) object is not behaving like an array. I am making an API call to a cloud function, which returns an object containing an array of games. I setState this array of games, but the child component does not recognize it as an array.

"games" does not have a length property.

Cloud function:

exports.getUserOwnedGames = functions.https.onCall(id => {
  return new Promise((resolve, reject) => {
    return steam.getUserOwnedGames(id).then(res => {
      resolve(res);
    });
  });
});

Client call:

export default class API {
  static getUserOwnedGames(id) {
    return functions
      .httpsCallable("getUserOwnedGames")("1234567890") // TEMP
      .then(result => {
        const userOwnedGames = result.data;
        return { games: userOwnedGames };
      });
  }
}

Parent component:

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      games: false
    };
  }

  loadData = () => {
    API.getUserOwnedGames("test").then(result => {
      console.log(result);
      console.log(result.games);
      this.setState({ games: result.games });
    });
  };

  componentDidMount() {
    this.loadData();
  }

  render() {
    const { games } = this.state;
    return (
      <div className="App">
        <header className="App-header">
          <GameLib games={games} />
        </header>
      </div>
    );
  }
}

Child component:

function GameLib(games) {
  if (games.length > 0) {
    return games.map(game => {
      return (
        <div>
          <p>{game.name}</p>
        </div>
      );
    });
  } else {
    return (
      <div>
        <p>No Games! Boring</p>
      </div>
    );
  }
}

console.log(result):

{games: Array(32)}
5
  • What's the error you're getting? Commented Aug 9, 2019 at 6:36
  • games.length > 0 never resolves to true. games does not have a "length" property. Commented Aug 9, 2019 at 6:39
  • Is that the exact error you're getting? Try Array.from(games). Commented Aug 9, 2019 at 6:42
  • @T_R_U_T_H check my answer and let me know if it helps. Commented Aug 9, 2019 at 6:46
  • Thank you for the help all, my API suddenly stopped working entirely... I am trying to fix it. Commented Aug 9, 2019 at 6:56

4 Answers 4

2

your initial state should be an empty array

constructor(props) {
    super(props);
    this.state = {
      games: []
   };
 }

as for child component, try this: ({games})

function GameLib({ games }) { // not (games) which is props
  if (games.length > 0) {
    return games.map(game => {
      return (
        <div>
          <p>{game.name}</p>
        </div>
      );
    });
  } else {
    return (
      <div>
        <p>No Games! Boring</p>
      </div>
    );
  }
}
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you Kengres but that does not affect the problem.
try passing props as parameters in constructor and in super, I didn't see it before, but in React Class that's super important
see the edit of my answer. the child component was wrong
I believe you are right that I needed ({games}). I will confirm as soon as I can.
Confirmed, marked your question as the answer. Thanks for the catch!
2

This is because your initial state is,

this.state = {
   games: false
};

you need to do this,

this.state = {
   games: []
};

Your component render first with default state and then your componentDidMount executes.

In your child component you need to do this,

function GameLib({games}) {

Comments

0

The problem is with your 'games' state in the parent component. In the constructor you have defined 'games' as a Boolean and set it's initial value as false.

constructor() {
 super();
 this.state = {
  games: false // This should be games: []
 }
}

Set it to an empty array as mentioned above. Next problem lies with your child component.

function GameLib(games) // either pass props or pass {games}

Comments

0

Your'e making an async call and initially passing an empty state Object to child component. Add loading state and when the loader resolves then load the child component. Something like this

this.state = {
   games: [],
   loading: true
}

loadData = () => {
    API.getUserOwnedGames("test").then(result => {
      console.log(result);
      console.log(result.games);
      this.setState({ games: result.games, loading: false });
    });
  };

 render() {
    const { games, loading } = this.state;
    if(loading){
    return(<div>Loading...</div>) 
    } else
    return (
      <div className="App">
        <header className="App-header">
          <GameLib games={games} />
        </header>
      </div>
    );
  }
}

Comments

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.