0

I am making my first steps with react and I'm struggling with the error message:

this.state.items.map is not a function

I already know that map is only a member of an array but not of objects. In the constructor of my App-class I initialized items[] explicit to an array.

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class HelloComponent extends React.Component {
  render() {
    return <div>Hello {this.props.name}</div>;
  }
}

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

  componentDidMount() {
    fetch(`http://example.com/api`)
      .then(result => {
        this.setState({ items: result.json() });
      }
      );
  }

  render() {
    var listItems = this.state.items.map(item => <HelloComponent name={item.name} />); // crash!!!

    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to React</h1>
        </header>
        <p className="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.

        {listItems}

        </p>
      </div>
    );
  }
}

export default App;

I don't know what happens. I have the suspicion that the call to result.json() may override my array with an promise but I have no idea how to implement it correctly.

3
  • 2
    You initialize it to an array, but then in componentDidMount(), in the fetch() callback, you set it to the response data. That may or may not be an array. Commented Feb 6, 2018 at 16:30
  • Are you sure that's an array? use console.log just to be sure of the datatype. Commented Feb 6, 2018 at 16:31
  • Is result.json an array too? an easy way to look for this kind of stuff is to do a console.log(this.state.items); in the render and watch out for what it prints during the whole loading. I bet you'll see an undefined value or an object. Commented Feb 6, 2018 at 16:31

2 Answers 2

2

I think your json response is the one overwriting the regular array, you should setState only from inside the json promise:

fetch(`http://example.com/api`)
  .then(result => {
    result.json().then(json => this.setState({ items: json }))
  }
);

Or, if you can support async/await, you can just await the result:

fetch(`http://example.com/api`)
  .then(result => {
    this.setState({ items: await result.json() })
  }
);
Sign up to request clarification or add additional context in comments.

1 Comment

The trick was that I wasn't completely aware of the fact that result.json() is really returning a promise.
1

i suggest you a way to achieve your goal

import request from 'request' // obtain by npm install --save request
class App extends Component {
    constructor() {
    super();
        this.state = { items: [] };
    }

componentDidMount() {
    request(`http://example.com/api`, (error, response, body) => {
        this.setState({ items: JSON.parse(body) };
    });
}

render() {
    var listItems = this.state.items.map(item => <HelloComponent name=
    {item.login} />); // worked!!!

return (
  <div className="App">
    <header className="App-header">
      <img src={logo} className="App-logo" alt="logo" />
      <h1 className="App-title">Welcome to React</h1>
    </header>
    <p className="App-intro">
      To get started, edit <code>src/App.js</code> and save to reload.

    {listItems}

    </p>
  </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.