React js simple get json and list contents "TypeError: this.state.items.map is not a function"

1.4k views Asked by At

I am new to React js and not javascript developer but can hack my way to solutions.

I have Django API url that is delivering simple array. I can successfully use axios.get to retrieve url json. But I cannot figure out how to use map to render the array contents as a simple list.

I get "TypeError: this.state.items.map is not a function"

My code:

import React from 'react';
import axios from 'axios';
import './App.css';

class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            items: []
        };
    }

    componentDidMount() {
        axios.get('http://localhost:8800/?format=json')
          .then(result => {
            this.setState({ items: result.data });
          });

    }

    render () { 
        return <ul>
          {this.state.items.map(item =>
            <li>{item} </li>)}
        </ul>
    }
}

export default App;

The response from axios.get is like this:

{
"users":"http://localhost:8800/users/?format=json",
"photos":"http://localhost:8800/photos/?format=json",
"teams":"http://localhost:8800/teams/?format=json"
}

I would like to render this as a HTML list:

users - http://localhost:8800/users/?format=json,
photos - http://localhost:8800/photos/?format=json,
teams - http://localhost:8800/teams/?format=json

The solution seems to be rewriting this part of code.

render () { 
    return <ul>
      {this.state.items.map((item, i) =>
        <li key>{item} </li>)}
    </ul>
}

I have seen many similar questions and answers but there are such as surprising variety of different situations and none apply to my specific case.

Can someone please point out:

a) what I am missing and b) what general React and/or javascript principle it relates to and c) any documentation where I could have understood this on my own?

2

There are 2 answers

3
Mikhail Katrin On BEST ANSWER

You can map Object keys

Object.keys(this.state.items) will return an array of keys ["users", "photos", "teams"] and then you can map this array

It will be better to load your data before component rendered

https://jsfiddle.net/qnqeL65b/

Change componentDidMount() on componentWillMount()

render () { 
    return (
        <ul>
        {
            Object.keys(this.state.items).map(key => {
                return (
                    <li>
                        {key} - {this.state.items[key]}
                    </li>
                )
            }
        }
        </ul>
    )
}

Array.prototype.map() docs

Object.keys() docs

2
23k On

As others have said, Object does not have a map function. Instead you can do something like this:

Object.keys(this.state.items).map((key, index) => {
   // do something
});

Or also you can use a for in loop:

for (let key in this.state.items) {
    // do something
}


If you're looking for key, value access, give this a try.

const obj = { 
  "first": "hello", 
  "second": "goodbye"
};

for (const [key, value] of Object.entries(obj)) {
  console.log(`${key}, ${value}`);
}

// "first, hello"
// "second, goodbye"