Stef
Stef

Reputation: 369

Nested axios api request / call not rendering in child component reactjs

I'm stuck. I'm trying to do a nested api call and then pass the result to state in the parent components and then pass state as props to a child component.

The calls seem to work and the props seem to get passed (I'm able to console log them out from the render method of the child component) but they won't actually render in the child component.

I strongly suspect I've made an error in the api call(s) but I can't put my finger on what it is. I've been using another answer on there as a template but something isn't happening:

Code in App.js (parent):

import React from 'react';
import atom from './api/atom';
import axios from 'axios';
import Documents from './components/Documents';
class App extends React.Component {
    state = {
        parents: [],
        posts: [],      
    };

      async getPosts () {
          let corsUrl = 'https://cors-anywhere.herokuapp.com/';
          let atomUrl = 'http://baseurl.co.uk/';
          let endpoint = 'api/informationobjects';
          let headers = {'Authorization': 'Basic ' + btoa('[email protected]:pwd')};

          axios.get(corsUrl + atomUrl + endpoint, {
            headers: headers,
          })
          .then(( response ) => {
            let items = response.data.results;
            let itemArray = [];

            // wait for nested calls to finish
            return Promise.all(items.map((item, index) => {
                return axios.get(corsUrl + atomUrl + endpoint + "/" + item.slug, {
                  headers: headers,
                })
                .then((response) => {
                  itemArray.push(response);
                }).then(this.setState({'posts': itemArray}))
            }));
            }
          )
          .catch(error => console.log("outer error: ", error));  
        }

    componentDidMount() {
      this.getPosts();
    }

    render() {
      return (
        <div>
            <h1>App.js</h1>
            <Documents posts={this.state.posts} />
        </div>      
      );
    }
};

export default App;

Code in Documents.js (child):

import React from 'react';

class Documents extends React.Component {

    render() {
        console.log("props: ", this.props.posts);

        return (
            <div>
                <hr />
                <h1>Documents.js</h1>
                <ul>posts: 
                    {this.props.posts.map((item, index) => {
                        return <li>test</li>
                    })}
                </ul>
            </div>
        );
    }
}

export default Documents;

As I say, I heavily suspect that the issue is in the nested async call. I followed the template given in this answer: ReactJS setState when all nested Axios calls are finished as far as I could but it isn't working.

I'm fairly new to react and working with apis so it may well be something glaringly obvious to someone more experienced.

Thanks in advance.

addition

I forgot to mention, there are no error messages of any kind. The test list items simply don't render.

Upvotes: 0

Views: 1046

Answers (2)

Olivier Boiss&#233;
Olivier Boiss&#233;

Reputation: 18113

then accepts a function in parameter, doing .then(this.setState({'posts': itemArray})) is not valid.

By the way Promise.all already returns an array with the resolved values so you don't need to create an array manually

You can try this code :

async getPosts () {
  const corsUrl = 'https://cors-anywhere.herokuapp.com/';
  const atomUrl = 'http://baseurl.co.uk/';
  const endpoint = 'api/informationobjects';
  const headers = {'Authorization': 'Basic ' + btoa('[email protected]:pwd')};
  const baseUrl = corsUrl + atomUrl + endpoint;

  axios.get(baseUrl, {headers})
    .then(response => {
      const promises = response.data.results
        .map(item => axios.get(`${baseUrl}/${item.slug}`, {headers}));

      Promise.all(promises)
        .then(posts => this.setState({posts}));
        .catch(error => console.log("outer error: ", error)); 
    }); 
}

Upvotes: 1

Beginner
Beginner

Reputation: 9105

Since when the api call happens its a future call so at the moment the posts array will be empty and initial render of the child will happen so you need to have a check and pass the posts when it gets updated

As you mentioned if the posts are coming try updating with below code

{
  this.state.posts.length && 
   <Documents posts={this.state.posts} />
}

Upvotes: 0

Related Questions