1

I'm pretty new to React and I've been struggling with fetching the data for quite a few days for my first React project.

I basically have a list of cards, split in two components: CardsList and Card. What I'm trying to do is to get the data for each card. My problem is, that I barely understood how fetching works for a single endpoint, and trying to fetch data from multiple endpoints at the same time seems to beat me.

I tried following an example from a blog explaining fetch, and came up with this:

export default class CardsList extends React.Component {
constructor(props) {
    super(props);

    this.state = {
        details: [],
        attachments: []
    };
}


componentDidMount() {

    //API and DEFAULT_QUERY have been set here, don't mind the ellipses
    var API = '...';
    var DEFAULT_QUERY = this.props.data;


    var apiRequest1 = fetch(API + DEFAULT_QUERY, {
        method: 'GET',
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
        },
        credentials: 'include',
    }).then(response => response.json());

    var apiRequest2 = fetch(API + DEFAULT_QUERY + '_attachment', {
        method: 'GET',
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
        },
        credentials: 'include',
    }).then(response => response.json());

    var combinedData = {"apiRequest1":{},"apiRequest2":{}};
    Promise.all([apiRequest1, apiRequest2]).then( values => {
        combinedData["apiRequest1"] = values[0];
        combinedData["apiRequest2"] = values[1];
        return combinedData;
    });
}

render() {

    const { combinedData } = this.state;

    let list = [];
    for(var item of combinedData["apiRequest2"]) {
        list.push(
            <Card data={item} key={list.length}/>
        );
    }

    return (
        <div className="container">
            <div className="row">
                {list}
            </div>
        </div>
    );
}}

As a first attempt I tried to feed the card component only the data from the second fetch. The console shows: "Uncaught TypeError: Cannot read property 'apiRequest2' of undefined".

I'm trying to learn a little bit from everywhere but I'm probably making things more confusing. What am I doing wrong and how should I go about this? Apologizes if I might seem confusing too.

EDIT: On the first fetch I'm trying to get the title, author and date of the card and on the second fetch I'm trying to get the preview image of the card.

The first fetch is something like this: data:[{title: "test", body: "test", author: "1", id: "1",...},…

and the second fetch: data:[{image_url: "abc.png", id: "1",...},...

2
  • Are you getting the list of Cards on the first request and then get details on the second one? Can you please tell more about what are you trying to fetch and an example of possible responses please? Commented Sep 22, 2017 at 17:57
  • Edited the post. Commented Sep 22, 2017 at 18:13

1 Answer 1

1

The problem is in this line

const { combinedData } = this.state;

It equals to this

var combinedData = this.state.combinedData;

and I'm sure that this.state.combinedData is undefined; so this exception is thrown

Uncaught TypeError: Cannot read property 'apiRequest2' of undefined"

You'll need to add the default value for this.state.combinedData at the constructor so that the first render won't fail. After that you'll need to call

this.setState({
  combinedData: ... // your data
})

at somepoint when your fetch request resolves.

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

5 Comments

Alright, I have set the default state of the this.state.combinedData to an empty array in the constructor. However, I'm a little unsure about where should I set the new state of combinedData. I added this.setState({combinedData : combinedData}) inside the componentDidMount() right after the Promise.all, but I'm getting "Uncaught TypeError: Cannot read property 'Symbol(Symbol.iterator)' of undefined". Should I have removed the line you have mentioned first?
@JaneEyre: I think you should replace return combinedData; with the this.setState... The idea here is to update the state after you finish fetching the data. After the state is updated by this.setState, react will call the render() method automatically.
@Định Trần: I thought of replacing the return combinedData with this.setState... too , but I get the same error for some reason. Both times I made changes, the error itself points to the line where the combinedData is used in the for loop. Could the problem be something else?
Alright, I have set the default state of the this.state.combinedData to an empty array in the constructor. combinedData["apiRequest2"] is undefined. You can set debugger and check for yourself. `[]["something"] will return undefined.
I finally got it! Thank you! I went back to having "details" and "attachments" as states and realized that on state update I wasn't giving the proper values, that's why the for loop wasn't working. So basically I should have used: this.setState({info : combinedData["apiRequest1"].data, attachments: combinedData["apiRequest2"].data}); I didn't pay attention to the data part.

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.