1

I'm trying to access an array within an object. The object form is:

{memes : { 
    data: {memes: Array(100)}
    success: true 
}}

import React from 'react';
import API from './functions/api';
import styles from './App.module.css';

class App extends React.Component {

  state = {
    memes: []
  }

  componentDidMount(){
    API.get().then(
      res => {
        // axios function returns Object
        const memes = res.data

        this.setState({ memes })
      }
    )
  }

  displayMemes(){

    console.log( this.state.memes );
    
    // memes: {
    //   data: {
    //     memes: Array(100)
    //   }
    // }

    this.state.memes.data.memes.forEach( meme => { 
      // Cannot read properties of undefined (reading 'forEach')...
    });
  }

  render(){
    return(
      <div className={ styles.container }>
        { this.displayMemes() }
      </div>
    )
  }
}

export default App;

Clearly I don't know what I'm doing wrong, I'm fairly new to this, the solution has to be simple.

I'm trying to get data from an open API ('https://api.imgflip.com/get_memes') to practise implementing different types of React apps.

4
  • 3
    Potentially multiple issues: You initialize this.state.memes to be an empty array (memes: []) and arrays don't have a data property (this.state.memes.data.memes.forEach(...)). Initialize the data to match what your code expects. Also if console.log(this.state.memes) displays {memes: ...} then that means this.state.memes actually has a property memes, so you would need to access this.state.memes.memes..... You should take a step back, think about how you want the data to look like that your component operators on and then make sure that you set that data correctly. Commented Mar 30, 2022 at 12:36
  • Try to console.log(this.state.memes) and see what you are getting. Commented Mar 30, 2022 at 12:38
  • Please check your res.data on API get. If res.data has only: memes: [.....], then you may use de-structuring and try replacing: const memes = res.data with const {memes} = res.data;. Also, please see if you are able to use ?. -> Optional chaining. So, instead of this.state.memes... you may try this.state?.memes?.data?...... Commented Mar 30, 2022 at 12:45
  • @FelixKling after retrieving the data from the API it comes in the form: Object.memes.data.data.memes, it's not great I know. The code I posted above is quickly trying to get things to work, and how I overlooked the need to check that the data exists before I set anything. Commented Mar 30, 2022 at 13:24

3 Answers 3

1

Calling an API is an asynchronous action which takes some time to resolve.
You can initialize memes with a null value first.

state = {
  memes: null
}

Check if memes is not null before calling displayMemes so that you prevent calling it before getting the API response.

  render(){
    return(
      <div className={styles.container}>
        {this.state.memes && this.displayMemes()}
      </div>
    )
  }
Sign up to request clarification or add additional context in comments.

Comments

0
        const memes = res.data.memes

        this.setState({ memes })

Comments

0

The forEach function always returns undefined after traversing through the array. Change it to map which returns an array.

class App extends React.Component {
  state = {
    memes: null,
    isLoading: true
  };

  componentDidMount() {
    fetch("https://api.imgflip.com/get_memes")
      .then((res) => res.json())
      .then((memes) => {
        this.setState({ memes });
        this.setState({ isLoading: false });
      });
  }

  displayMemes() {
    return this.state.memes.data.memes.map((meme) => {
      return <div>{meme.name}</div>;
    })
  }

  render() {
    return this.state.isLoading ? "No memes" : <div>{this.displayMemes()}</div>;
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

I added isLoading to call displayMemes when data has been fetched.

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.