0

I am working on a hacker news clone I am trying to get the ids of the top stories from their api using axios in componentDidMount and then making another axios call to get the stories and push them in a state array but when I try to map over and render that array nothing shows up

class App extends Component {

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

  componentDidMount() {
    axios.get('https://hacker-news.firebaseio.com/v0/topstories.json')
      .then( result => {
        result.data.slice(0, 10).forEach(element => {
          axios.get('https://hacker-news.firebaseio.com/v0/item/' + element + '.json')
            .then( value => {
              this.state.posts.push(value)
            })
            .catch(err =>{
              console.log(err)
            })
        })
      })
      .catch(err => {
          console.log(err);
      })
  }


  render() {
    return (
    <div>
      <Header title="Hacker News" />
      {this.state.posts.map( (element, index) => <Post key={element.data.id} serialNum={index} postTitle={element.data.title} postVotes={element.data.score} postAuthor={element.data.by} />) }
    </div> 
    )
  }
}
2
  • 1
    Dont do this: this.state.posts.push(value) Instead, create an array and do this.setState({ posts: newArray }) Commented Feb 22, 2019 at 7:09
  • Yeah I tried that too still doesn't show up, the weird thing is that when I try to console.log(this.state.posts) the array correctly shows up in the console but nothing shows up in the render Commented Feb 22, 2019 at 7:17

3 Answers 3

1

Try setting the state like this:

 axios.get('https://hacker-news.firebaseio.com/v0/item/' + element + '.json')
            .then( value => {
              this.setState({
                posts: [value, ...this.state.posts]
              })
            })
            .catch(err =>{
              console.log(err)
            })
        })

This way you're using setState and appending every new value to the existing state.

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

Comments

0

As stated in the comments, don't use push for set state. In your code when you make the second request you must change the setState method to spread out the new value.

class App extends React.Component {

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

  componentDidMount() {
    axios.get('https://hacker-news.firebaseio.com/v0/topstories.json')
      .then( result => {
        result.data.slice(0, 10).forEach(element => {
          axios.get('https://hacker-news.firebaseio.com/v0/item/' + element + '.json')
            .then( value => {
               this.setState(prevState => ({posts: [ value.data, ...prevState.posts]}))
            })
            .catch(err =>{
                console.log("err");
                console.log(err);
            })
        })
      })
      .catch(err => {
          console.log(err);
      })
  }


  render() {
    return (
       <div>
          {this.state.posts && this.state.posts.map( (element, index) => 
             <div key={element.id}>
                {element.title}
             </div>
          )}
        </div> 
    );
  }
 }

Comments

0

componentDidMount() is called after Render() only once. React doesn't know about the state changes unless you use setState().

componentDidMount() {
    axios.get('https://hacker-news.firebaseio.com/v0/topstories.json')
      .then( result => {
        result.data.slice(0, 10).forEach(element => {
          axios.get('https://hacker-news.firebaseio.com/v0/item/' + element + '.json')
            .then( value => {
              this.setState({posts: [value, ...this.state.posts]})
            })
           })
         })
        }

Use this.setState({posts : [value, ...this.state.posts]}) instead of this.state.posts.push(value). using ... (spread operator) appends the value to the original posts array.

2 Comments

If you're using async/await there's no need to chain .then and .catch. And this wont to the trick. this.state.posts will only contain the last post from hacker-news since you're replacing the state in the forEach loop
Thanks for correction. I use seperate methods for http calls hence it's become a habit. The problem was that he was using push which react doesn't know as a state change. It's better to extract the http call in a seperate method and await the response.

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.