0

I'm new to React and I'm trying to build (for now) a simple app that allows you to search for a name in a list of transactions and return the transaction details to you. So far I have been struggling to deal with the API request and I keep running into errors. I'm using superagent for my API calls

    import React, {Component } from 'react';
    import Request from 'superagent'
    import './App.css';

    class App extends Component {
      constructor() {
        super();
        this.state = {};
      }

      componentWillMount() {
        var url = 'https://api.myjson.com/bins/2dorw';

        Request.get(url).then((response) => {
          this.setState({
            items: response.body.items,
          });
        });
      }

      render() {
        var names = this.state.items.map((name, index) => {
            <div>
                <li key={index}> {this.state.items.merchant.name } </li>
            </div>
        });

        return ( 
            <div className="App">
                {names}
            </div>
        );
      }
    }

    export default App;

I can't even make this simple API call to work, just display the names from the API endpoint. This has been going on for a day or so, and usually I get the object either null, undefined and type errors.

Uncaught (in promise) TypeError: Cannot read property '_currentElement' of null(…)

App.js:64 Uncaught TypeError: Cannot read property 'map' of undefined

I have tried following tutorials but I haven't been able to find one that would work in my case, so I can't wrap my head around the API call.

UPDATE

After changing to componentDidMount(), adding isFetching and setting items to an array in setState (as the two answers have suggested), I am now getting an

Uncaught (in promise) TypeError: Cannot read property 'name' of undefined

2 Answers 2

1

Using componentWillMount() is slightly early in the lifecycle. Wait until it has mounted using componentDidMount() That should help resolve the first error being thrown.

The second error comes from this.state.items.map when the items have not shown up yet. I would also suggest adding a isFetching state, to check if the data has shown up yet.:

 class App extends Component {

  constructor() {
    super();
    this.state = {
      isFetching: true
    };
  }

  componentDidMount() {
    var url = 'https://api.myjson.com/bins/2dorw';
    Request.get(url).then((response) => {
      this.setState({
        items: response.body.items,
        isFetching: false
      });  
    });
  }


  render() {
    if (this.state.isFetching) return null;

    var names = this.state.items.map((item, index) => { 
      <div>
        <li key={index}> {item.merchant.name} </li>
      </div >
    });

    return (
      <div className="App">
        {names}
      </div>
    );
  }
}

export default App;

Update

Added a slight change - looks like your map function was also a bit off. It's hard to say what exactly you are looking for, because I don't know the data structure exactly.

You had

var names = this.state.items.map((name, index) => {
    <div>
        <li key={index}> {this.state.items.merchant.name } </li>
    </div>
});

Passing name as the first param, which is the entire item. You then call this.state all over again - which you shouldn't need to do. I think this is where some of the undefined issues are coming from as well.

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

2 Comments

Tried the above but it just gives me another error. Uncaught (in promise) TypeError: Cannot read property 'name' of undefined Most of my errors are tied to the "undefined" that keeps popping up.
Ok - I updated - without the actual data structure of items it's hard to say what the actual code should be - but hoping this helps. @Wink207
0

this.state.items is undefined because you declared state = {}, so can not map over it. You can fix this problem by making items an empty array.

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

4 Comments

Right. This would be the other way to resolve it. Probably will depend on what the goal is there, whether rendering something vs empty is more important.
Yes it depends on what one wants to achieve :)
Though its an anti pattern to not defining what items will look like in the state
I and a bunch of our devs encountered this over and over again - not initializing some state properly or otherwise dealing with race conditions related to lifecycle methods, async data fetches, etc. - so I ultimately decided to create a lib that simplifies a lot of this for many use cases: github.com/DigitalGlobe/jetset

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.