0

I am new to React and am running through a tutorial that uses the Poke API (https://pokeapi.co).

I am using whatwg-fetch to make requests to the API. This saves data from the API as an object to the state 'selectedPokemon'.

    this.state = {
      // other states
      showModal: false,
      selectedPokemon: null
    };

I want to send that data to a component (in my case a modal), so I updated my modal component call to include the selectedPokemon state as a prop:

<PokemonModal pokemon={this.state.selectedPokemon} closeModal={this.handleModalClose} showModal={this.state.showModal} />

I also updated my PokemonModal component (on PokemonModal.js) to include pokemon as a prop:

const PokemonModal = ({showModal, closeModal, pokemon}) => {

However, when I go to use that prop within PokemonModal, eg:

<Modal.Title>{pokemon.name}</Modal.Title>

I get an error

Uncaught TypeError: Cannot read property 'name' of null

(This is the same with any other part of the object I try to use eg pokemon.order. The showModal and closeModal props work as expected.)

Would anyone know how I could send and use a JSON object to another component?


If it matters, my fetch function is set up as such. The console.log returns the expected result, which is the object from: https://pokeapi.co/api/v2/pokemon/10125/

  handleModalOpen(pokemon) {
    if(pokemon.url !== undefined) {
      fetch(`${pokemon.url}`)
        .then(response => {
          return response.json();
        })
        .then(json => {
          this.setState({
            selectedPokemon: json,
            showModal: true
          }) 
          console.log('selected: ' + this.state.selectedPokemon);
        })
        .catch(ex => {
          console.log('pasrsing failed ' + ex);
        })
    }
  }

3 Answers 3

1

The selectedPokemon would be undefined untill the request to pokemon.url finishes.

And thus, Initially the <PokemonModal .../> will receive pokemon as undefined. Because of which, you are seeing the error.

One way to solve it would be to have an if in the PokemonModal component:

const PokemonModal = ({showModal, closeModal, pokemon}) => {
    if(pokemon && Object.keys(pokemon).length !== 0) {
        // prepare the view and return it
    }
    return null;
}

You can also have an if on your parent component too, But generally speaking, I like to have the if in child component so that the parent component would not get cluttered by so many ifs

Sign up to request clarification or add additional context in comments.

Comments

1

The reason you get a TypeError, is because you initialize your state with null, and while waiting to the response the modal tried to read the name property of pokemon. you need to handle the case when there is no pokemon set yet inside the modal, when rendering you can add const PokemonModal = ({showModal, closeModal, pokemon}) => { if (!pokemon) {return "Loading..."}` } or some loading spinner.

no need to use JSON in here imho

Comments

0

setState is async, that's why your component is failing, as you are opening the modal, but the state might not have been set and propagated to the children yet. one way to solve this is to add a loading state to your modal.

return (
pokemon&&{
    <Modal>
      <Modal.Title>{pokemon.name}</Modal.Title>
    </Modal>
}

)

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.